Mercurial > hvf > hvf-old
changeset 441:dc0825c5ca65
Merge branch 'master' into loader
Conflicts:
cp/Makefile
cp/include/loader.h
cp/ipl/ipl_rdr.S
cp/ipl/ipl_tape.S_in
cp/ipl/linker.script
cp/ipl/loader.c
cp/ipl/loader_asm.S
cp/ipl/setmode.S
cp/scripts/gen_rdr_ccws.sh
cp/scripts/gen_tape_ipl_s.sh
loader/eckd.S
loader/linker.script
loader/loader_asm.S
loader/setmode.S
sys/ipl/ipl_rdr.S
sys/ipl/linker.script
sys/ipl/loader_asm.S
sys/ipl/setmode.S
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Fri, 18 Jun 2010 20:41:48 -0400 |
parents | b438de5471bc (current diff) 0c8d5e3e591f (diff) |
children | 3574cdf8705a |
files | Makefile cp/Makefile cp/scripts/Makefile.commands loader/Makefile sys/.gitignore sys/Makefile sys/cp/Makefile sys/cp/cmd_beginstop.c sys/cp/cmd_display.c sys/cp/cmd_enable.c sys/cp/cmd_helpers.c sys/cp/cmd_logon.c sys/cp/cmd_query.c sys/cp/cmd_set.c sys/cp/cmd_store.c sys/cp/cmd_system.c sys/cp/cmds.c sys/cp/directory.c sys/cp/disassm.c sys/cp/exception.c sys/cp/guest.c sys/cp/guest_ipl.S sys/cp/init.c sys/cp/instruction.c sys/cp/instruction_priv.c sys/cp/intercept.c sys/cp/reset.c sys/cp/splash.c sys/doc/.gitignore sys/doc/PSA.txt sys/doc/ipl.txt sys/doc/memory.txt sys/drivers/3215.c sys/drivers/Makefile sys/drivers/console.c sys/drivers/dasd.c sys/drivers/device.c sys/drivers/vdevice.c sys/fs/Makefile sys/fs/bdev.c sys/fs/edf.c sys/hvf.directory sys/include/atomic.h sys/include/bdev.h sys/include/buddy.h sys/include/channel.h sys/include/compiler.h sys/include/config.h sys/include/console.h sys/include/cp.h sys/include/cpu.h sys/include/dat.h sys/include/device.h sys/include/directory.h sys/include/disassm.h sys/include/ebcdic.h sys/include/edf.h sys/include/interrupt.h sys/include/io.h sys/include/list.h sys/include/magic.h sys/include/mm.h sys/include/mutex.h sys/include/nucleus.h sys/include/page.h sys/include/sched.h sys/include/sie.h sys/include/slab.h sys/include/spinlock.h sys/include/splash.h sys/include/vcpu.h sys/include/vdevice.h sys/mm/Makefile sys/mm/buddy.c sys/mm/dat.c sys/mm/page.c sys/mm/slab.c sys/nucleus/Makefile sys/nucleus/ebcdic.c sys/nucleus/ext.c sys/nucleus/init.c sys/nucleus/int.S sys/nucleus/io.c sys/nucleus/mutex.c sys/nucleus/pgm.c sys/nucleus/printf.c sys/nucleus/sched.c sys/nucleus/spinlock.c sys/nucleus/svc.c sys/scripts/Makefile.build sys/scripts/Makefile.commands sys/scripts/extract-version.sh sys/scripts/gen-dir.sh sys/scripts/gen-docs.sh sys/scripts/linker.script sys/scripts/pad.sh |
diffstat | 203 files changed, 10846 insertions(+), 10132 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Tue Dec 29 20:04:16 2009 -0500 +++ b/Makefile Fri Jun 18 20:41:48 2010 -0400 @@ -8,7 +8,7 @@ all: make -C lib - make -C sys + make -C cp make -C nss/8ball make -C loader @@ -17,7 +17,7 @@ clean: make -C lib clean - make -C sys clean + make -C cp clean make -C nss/8ball clean make -C loader clean make -C doc/manual clean
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/.gitignore Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,9 @@ +*.o +*.rto +ipl/ipl_rdr_ccws.S +ipl/ipl_tape.S +shell/directory_structs.c +hvf +loader_rdr.bin +loader_tape.bin +cscope.out
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/Makefile Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,75 @@ +# +# HVF: Hobbyist Virtualization Facility +# +# (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> +# +# This file is released under the GPLv2. See the COPYING file for more +# details. +# + +VERSION=0.16-rc2 + +AS=$(CROSS_COMPILE)as +CC=$(CROSS_COMPILE)gcc +LD=$(CROSS_COMPILE)ld +OBJCOPY=$(CROSS_COMPILE)objcopy + +# By default, be terse +V=0 + +DISPLAYVERSION=$(shell ./scripts/extract-version.sh) + +MAKEFLAGS += -rR --no-print-directory +CFLAGS=-DVERSION=\"$(DISPLAYVERSION)\" -g -fno-strict-aliasing -fno-builtin -nostdlib -Wall -m64 -I include/ -I ../include/ -O2 -include ../include/types.h +NUCLEUSCFLAGS=-include include/nucleus.h +LDFLAGS=-m elf64_s390 + +LIBS=clock digest string + +export AS CC LD OBJCOPY +export MAKEFLAGS CFLAGS NUCLEUSCFLAGS LDFLAGS + +TOP_DIRS=nucleus/ mm/ fs/ drivers/ shell/ + +.PHONY: all build clean mrproper cleanup hvfclean tags +.PHONY: $(TOP_DIRS) + +include scripts/Makefile.commands + +all: build hvf + @echo "Image is `stat -c %s hvf` bytes" + +hvf: $(patsubst %/,%/built-in.o,$(TOP_DIRS)) + $(call link-hvf,$^ $(patsubst %,../lib/%.a,$(LIBS)),$@) + +docs: + ./scripts/gen-docs.sh + +clean: + @$(MAKE) DIR=nucleus/ cleanup V=$V + @$(MAKE) DIR=mm/ cleanup V=$V + @$(MAKE) DIR=fs/ cleanup V=$V + @$(MAKE) DIR=drivers/ cleanup V=$V + @$(MAKE) DIR=shell/ cleanup V=$V + $(call clean,hvf) + $(call clean,shell/directory_structs.c) + $(call rclean,doc/commands) + +mrproper: clean + $(call clean,cscope.out ctags) + +cleanup: + $(call clean,$(DIR)*.o) + +build: $(TOP_DIRS) + +$(TOP_DIRS): %/: + @$(MAKE) -f scripts/Makefile.build DIR=$@ V=$V + +tags: + $(call cscope) + +# +# Include Makefiles from all the top level directories +# +include $(patsubst %/,%/Makefile,$(TOP_DIRS))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/doc/.gitignore Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,1 @@ +commands
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/doc/PSA.txt Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,8 @@ +Aside from the architecture defined storage locations in the PSA, HVF uses +the following addresses for special reasons: + +hex dec length reason + + 200 512 128 interrupt handler GPR storage + 280 640 16 PSW temporary storage + 290 656 8 current pointer
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/doc/ipl.txt Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,94 @@ +This file attempts to describe what happens during IPL. + +NOTE: At the time, only IPL from tape and card reader is supported. + +1) system reads 24 bytes from the device + + a) bytes 0-7: new PSW, no interrupts, start address 0x800000 (8MB) + + IPL from tape: + + b) bytes 8-15: CCW to rewind the tape to previous TM + + c) bytes 16-23: CCW to read the entire loader to 0x800000 (8 MB) + + IPL from card reader: + + b) bytes 8-15: CCW to read 80 bytes (containing up to 10 CCWs) to + 0x18 + + c) bytes 16-23: CCW to read 24 bytes (containing up to 3 CCWs) to 0x68 + + Command chaining starts reading CCWs from addres 0x18 on. These read + the loader to 0x800000 (8 MB) + +2) arch mode is changed to z/Arch (see ipl/setmode.S) + +3) temporary stack is set up (R15 being the pointer) (see ipl/setmode.S) + +4) loader begins to execute: function load_nucleus (see ipl/loader.c) + + NOTE: loader.c use static inlines extensively, and thefore stack usage is + minimal + + a) If the IPL was from a tape, a CCW is issues to seek to the next TM + + b) nucleus is read from tape to 0x400000 (4 MB) + + NOTE: the data at 4MB just read is a 64-bit s390 ELF binary with Linux + ABI bits + + i) addition CCW address is set in the ORB + + ii) __readnucleus() is called; this function is implemented in + assembly (see ipl/loader_asm.S) + + iii) IO interrupt handler is set up (implemented in asm, see + ipl/loader_asm.S) + + iv) ORB is sent to the subchannel + + v) interrupts are enabled + + vi) a new PSW with wait state bit set is loaded + + vii) on IO interrupt + + 1) TSCH is issued to fill in a IRB + + 2) magic value (ORB int param) is checked + + 3) Device End flag is checked in the IRB + + NOTE: more checks should be performed here + + 4) If the device end flag is set, return to code that set up the + interrupt handler + + 5) otherwise, load up the old IO PSW (the one with the wait + state) + + viii)return to caller (back to ipl/loader.c) + + c) verify ELF header magic number, machine, type, etc. values + + d) traverse the section headers & copy data to final destination + + i) if the section type is PROGBITS (data stored in the ELF), copy + the data from it's temporary location to the desired location + (destination, offset within file, and length are all stored in + the section header) - this takes care of .text, .data, and + .rodata sections + + ii) if the section type is NOBITS (uninitialized storage, e.g., + .bss), do nothing, just assume that the location is a valid + location in memory + + iii) skip any other section types + + NOTE: SYMTAB and STRTAB section types should be copied to a useful + location to allow for symbols to be looked up during nucleus execution + + e) jump to the entry point as indicated by the ELF header + +At this point, the nucleus is executing.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/doc/memory.txt Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,62 @@ +Physical locations: + +------------------- (2^64)-1 -- +| | \ +| | | + . | + . \ + . > Generic pages + . / + . | +| | | +| | / +|-----------------| f(memsize)-- +| | \ +| | | + . \ + . > struct page array (see below) + . / +| | | +| | / +|-----------------| 4M -- +| | \ +| | | + . \ + . > OS .text, .data, .rodata, .bss + . / +| | | +| | / +|-----------------| 1M -- +| | \ +| | | + . | + . | + . \ +| | > PSA for each CPU +| | / +|-----------------| 8k | +| | | +| PSA | | +| | / +------------------- 0 -- + + +0 - 1MB: + Divided into up to 128 8KB chunks; nth chunk is nth CPU's PSA + (mapping done via the prefix register). + +1MB - 4MB: + OS .text + OS .data + OS .rodata + OS .bss + +4MB - (4MB + roundup((memsize >> PAGE_SIZE) * sizeof(struct page))): + This is an array of struct page entries for each page in the system. + The size varies based on the amount of memory installed. + +?? - (2^64)-1: + Generic pages; used for nucleus & process data + + These pages are managed by the buddy allocator. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/drivers/3215.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,28 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <device.h> +#include <console.h> +#include <list.h> +#include <sched.h> +#include <directory.h> + +static struct device_type d3215 = { + .types = LIST_HEAD_INIT(d3215.types), + .reg = NULL, + .interrupt = NULL, + .enable = console_enable, + .snprintf = NULL, + .type = 0x3215, + .model = 0, +}; + +int register_driver_3215(void) +{ + return register_device_type(&d3215); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/drivers/Makefile Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,1 @@ +objs-drivers := device.o console.o 3215.o dasd.o vdevice.o
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/drivers/console.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,394 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <console.h> +#include <slab.h> +#include <sched.h> +#include <directory.h> +#include <splash.h> +#include <vsprintf.h> + +/* + * List of all consoles on the system + */ +static LIST_HEAD(consoles); +static spinlock_t consoles_lock = SPIN_LOCK_UNLOCKED; + +static int read_io_int_handler(struct device *dev, struct io_op *ioop, struct irb *irb) +{ + struct console_line *cline; + struct ccw *ccw; + void *ptr; + + /* Device End is set, we're done */ + if (!(irb->scsw.dev_status & 0x04)) { + ioop->err = -EAGAIN; + return 0; + } + + ccw = (struct ccw*) (u64) ioop->orb.addr; + ptr = (void*) (u64) ccw->addr; + cline = container_of(ptr, struct console_line, buf); + + cline->len = strnlen((char*) cline->buf, CON_MAX_LINE_LEN-1); + cline->state = CON_STATE_IO; + + ioop->err = 0; + return 0; +} + +static void do_issue_read(struct console *con, struct io_op *ioop, struct ccw *ccws) +{ + struct console_line *cline; + int found; + + found = 0; + + atomic_dec(&con->dev->attention); + + spin_lock(&con->lock); + list_for_each_entry(cline, &con->read_lines, lines) { + if (cline->state != CON_STATE_FREE) + continue; + + cline->state = CON_STATE_PENDING; + found = 1; + break; + } + + if (!found) { + /* + * No unused console lines, time to allocate a new one + */ + cline = malloc(CON_LINE_ALLOC_SIZE, ZONE_NORMAL); + BUG_ON(!cline); + + cline->state = CON_STATE_PENDING; + list_add_tail(&cline->lines, &con->read_lines); + } + spin_unlock(&con->lock); + + /* clear the buffer to allow strlen on the result */ + memset(cline->buf, 0, CON_MAX_LINE_LEN); + + memset(ccws, 0, sizeof(struct ccw)); + + ccws[0].addr = ADDR31(cline->buf); + ccws[0].count = CON_MAX_LINE_LEN - 1; + ccws[0].cmd = 0x0a; + ccws[0].flags = CCW_FLAG_SLI; + + memset(&ioop->orb, 0, sizeof(struct orb)); + ioop->orb.lpm = 0xff; + ioop->orb.addr = ADDR31(ccws); + ioop->orb.f = 1; + + ioop->handler = read_io_int_handler; + ioop->dtor = NULL; + + submit_io(con->dev, ioop, CAN_SLEEP); +} + +/** + * console_flusher - iterates over a console's buffers and initiates the IO + */ +static int console_flusher(void *data) +{ + struct console *con = data; + struct console_line *cline; + int free_count; + int ccw_count; + + /* needed for the IO */ + struct io_op ioop; + struct ccw ccws[CON_MAX_FLUSH_LINES]; + + for(;;) { + if (atomic_read(&con->dev->attention)) + do_issue_read(con, &ioop, ccws); + + spin_lock(&con->lock); + + /* + * free all the lines we just finished the IO for + */ + free_count = 0; + list_for_each_entry(cline, &con->write_lines, lines) { + if (cline->state != CON_STATE_IO) + continue; + + cline->state = CON_STATE_FREE; + free_count++; + + if (free_count > CON_MAX_FREE_LINES) { + list_del(&cline->lines); + free(cline); + } + } + + /* + * find at most CON_MAX_FLUSH_LINES of CON_STATE_PENDING + * lines and shove necessary information into the right + * CCW + */ + ccw_count = 0; + list_for_each_entry(cline, &con->write_lines, lines) { + if (ccw_count >= CON_MAX_FLUSH_LINES) + break; + + if (cline->state != CON_STATE_PENDING) + continue; + + cline->state = CON_STATE_IO; + + ccws[ccw_count].addr = ADDR31(cline->buf); + ccws[ccw_count].count = cline->len; + ccws[ccw_count].cmd = 0x01; /* write */ + ccws[ccw_count].flags = CCW_FLAG_CC | CCW_FLAG_SLI; + + ccw_count++; + } + + /* + * We don't need the lock anymore + */ + spin_unlock(&con->lock); + + /* + * Anything to do? + */ + if (!ccw_count) { + schedule(); + continue; + } + + /* + * Clear Command-Chaining on the last CCW + */ + ccws[ccw_count-1].flags &= ~CCW_FLAG_CC; + + /* + * Now, set up the ORB and CCW + */ + memset(&ioop.orb, 0, sizeof(struct orb)); + ioop.orb.lpm = 0xff; + ioop.orb.addr = ADDR31(ccws); + ioop.orb.f = 1; /* format 1 CCW */ + + /* + * Set up the operation handler pointers, and start the IO + */ + ioop.handler = NULL; + ioop.dtor = NULL; + + submit_io(con->dev, &ioop, CAN_SLEEP); + } + + return 0; +} + +/** + * register_console - generic device registration callback + * @dev: console device to register + */ +static int register_console(struct device *dev) +{ + struct console *con; + struct console_line *cline; + + dev_get(dev); + + con = malloc(sizeof(struct console), ZONE_NORMAL); + BUG_ON(!con); + + con->sys = NULL; + con->dev = dev; + con->lock = SPIN_LOCK_UNLOCKED; + INIT_LIST_HEAD(&con->write_lines); + INIT_LIST_HEAD(&con->read_lines); + + /* + * alloc one read-line + */ + cline = malloc(CON_LINE_ALLOC_SIZE, ZONE_NORMAL); + BUG_ON(!cline); + cline->state = CON_STATE_FREE; + list_add(&cline->lines, &con->read_lines); + + spin_lock(&consoles_lock); + list_add_tail(&con->consoles, &consoles); + spin_unlock(&consoles_lock); + + return 0; +} + +static void print_splash(struct console *con) +{ + int i; + + for(i = 0; splash[i]; i++) + con_printf(con, splash[i]); + + con_printf(con, "HVF VERSION " VERSION "\n\n"); +} + +struct console* start_oper_console(void) +{ + struct device *dev; + + /* + * We only start the operator console + */ + + dev = find_device_by_ccuu(OPER_CONSOLE_CCUU); + BUG_ON(IS_ERR(dev)); + + return console_enable(dev); +} + +void* console_enable(struct device *dev) +{ + char name[TASK_NAME_LEN+1]; + struct console *con; + + con = find_console(dev); + if (!IS_ERR(con)) + return con; + + if (register_console(dev)) + return ERR_PTR(-ENOMEM); + + /* try again, this time, we should always find it! */ + con = find_console(dev); + if (IS_ERR(con)) + return con; + + atomic_inc(&con->dev->in_use); + + snprintf(name, TASK_NAME_LEN, "%05X-conflsh", con->dev->sch); + + create_task(name, console_flusher, con); + + print_splash(con); + + return con; +} + +int con_read_pending(struct console *con) +{ + struct console_line *cline; + int ret = 0; + + spin_lock(&con->lock); + + list_for_each_entry(cline, &con->read_lines, lines) { + if (cline->state == CON_STATE_IO) { + ret = 1; + break; + } + } + + spin_unlock(&con->lock); + + return ret; +} + +int con_read(struct console *con, u8 *buf, int size) +{ + struct console_line *cline; + int len; + + spin_lock(&con->lock); + + list_for_each_entry(cline, &con->read_lines, lines) { + if (cline->state == CON_STATE_IO) + goto found; + } + + spin_unlock(&con->lock); + + return -1; + +found: + len = (size-1 < cline->len) ? size-1 : cline->len; + + memcpy(buf, cline->buf, len); + buf[len] = '\0'; + + cline->state = CON_STATE_FREE; + + spin_unlock(&con->lock); + + return len; +} + +int con_write(struct console *con, u8 *buf, int len) +{ + int bytes = 0; + struct console_line *cline; + + spin_lock(&con->lock); + + list_for_each_entry(cline, &con->write_lines, lines) { + if (cline->state == CON_STATE_FREE) + goto found; + } + + /* None found, can we allocate a new one? */ + cline = malloc(CON_LINE_ALLOC_SIZE, ZONE_NORMAL); + if (!cline) + goto abort; + + list_add_tail(&cline->lines, &con->write_lines); + +found: + cline->state = CON_STATE_PENDING; + + cline->len = (len < CON_MAX_LINE_LEN) ? len : CON_MAX_LINE_LEN; + memcpy(cline->buf, buf, cline->len); + + /* + * All done here. The async thread will pick up the line of text, + * and issue the IO. + */ + +abort: + spin_unlock(&con->lock); + + return bytes; +} + +void for_each_console(void (*f)(struct console *con)) +{ + struct console *con; + + if (!f) + return; + + spin_lock(&consoles_lock); + list_for_each_entry(con, &consoles, consoles) + f(con); + spin_unlock(&consoles_lock); +} + +struct console* find_console(struct device *dev) +{ + struct console *con; + + if (!dev) + return ERR_PTR(-ENOENT); + + spin_lock(&consoles_lock); + list_for_each_entry(con, &consoles, consoles) { + if (con->dev == dev) + goto found; + } + con = ERR_PTR(-ENOENT); +found: + spin_unlock(&consoles_lock); + return con; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/drivers/dasd.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,283 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <device.h> +#include <console.h> +#include <list.h> +#include <io.h> +#include <sched.h> +#include <vsprintf.h> + +static int d3390_snprintf(struct device *dev, char* buf, int len) +{ + return snprintf(buf, len, "%10d CYL ", dev->eckd.cyls); +} + +static inline unsigned int ceil_quot(unsigned int d1, unsigned int d2) +{ + return (d1 + (d2 - 1)) / d2; +} + +static inline int d3390_recs_per_track(int kl, int dl) +{ + int dn, kn; + + dn = ceil_quot(dl + 6, 232) + 1; + if (kl) { + kn = ceil_quot(kl + 6, 232) + 1; + return 1729 / (10 + 9 + ceil_quot(kl + 6 * kn, 34) + + 9 + ceil_quot(dl + 6 * dn, 34)); + } else + return 1729 / (10 + 9 + ceil_quot(dl + 6 * dn, 34)); +} + +static int d3390_reg(struct device *dev) +{ + struct io_op ioop; + struct ccw ccw; + int ret; + u8 buf[64]; + + switch(dev->model) { + case 0x02: /* 3390, 3390-1 */ + case 0x06: /* 3390-2 */ + case 0x0a: /* 3390-3 */ + case 0x0c: /* 3390-9, 3390-27, 3390-J, 3390-54, 3390-JJ */ + break; + default: + return -ENOENT; + } + + /* + * Set up IO op for Read Device Characteristics + */ + ioop.handler = NULL; + ioop.dtor = NULL; + + memset(&ioop.orb, 0, sizeof(struct orb)); + ioop.orb.lpm = 0xff; + ioop.orb.addr = ADDR31(&ccw); + ioop.orb.f = 1; + + memset(&ccw, 0, sizeof(struct ccw)); + ccw.cmd = 0x64; /* RDC */ + ccw.flags = CCW_FLAG_SLI; + ccw.count = 64; + ccw.addr = ADDR31(buf); + + /* + * issue RDC + */ + ret = submit_io(dev, &ioop, CAN_LOOP); + if (ret) + return ret; + + dev->eckd.cyls = (buf[12] << 8) | + buf[13]; + dev->eckd.tracks = (buf[14] << 8) | + buf[15]; + dev->eckd.recs = d3390_recs_per_track(0, 4096); + dev->eckd.sectors = buf[16]; + dev->eckd.len = (buf[18] << 8) | + buf[19]; + + dev->eckd.formula = buf[22]; + if (dev->eckd.formula == 1) { + dev->eckd.f1 = buf[23]; + dev->eckd.f2 = (buf[24] << 8) | + buf[25]; + dev->eckd.f3 = (buf[26] << 8) | + buf[27]; + dev->eckd.f4 = 0; + dev->eckd.f5 = 0; + } else if (dev->eckd.formula == 2) { + dev->eckd.f1 = buf[23]; + dev->eckd.f2 = buf[24]; + dev->eckd.f3 = buf[25]; + dev->eckd.f4 = buf[26]; + dev->eckd.f5 = buf[27]; + } else + return -EINVAL; + + return 0; +} + +static int d3390_read(struct device *dev, u8 *buf, int lba) +{ + struct io_op ioop; + struct ccw ccw[4]; + u8 seek_data[6]; + u8 search_data[5]; + int ret; + + u16 cc, hh, r; + int rpt = dev->eckd.recs; + int rpc = dev->eckd.tracks * rpt; + + if (lba < 1) + return -EINVAL; + + lba--; + cc = lba / rpc; + hh = (lba % rpc) / rpt; + r = (lba % rpc) % rpt; + r++; + + /* + * Set up IO op + */ + ioop.handler = NULL; + ioop.dtor = NULL; + + memset(&ioop.orb, 0, sizeof(struct orb)); + ioop.orb.lpm = 0xff; + ioop.orb.addr = ADDR31(ccw); + ioop.orb.f = 1; + + memset(ccw, 0, sizeof(ccw)); + + /* SEEK */ + ccw[0].cmd = 0x07; + ccw[0].flags = CCW_FLAG_CC | CCW_FLAG_SLI; + ccw[0].count = 6; + ccw[0].addr = ADDR31(seek_data); + + seek_data[0] = 0; /* zero */ + seek_data[1] = 0; /* zero */ + seek_data[2] = cc >> 8; /* Cc */ + seek_data[3] = cc & 0xff; /* cC */ + seek_data[4] = hh >> 8; /* Hh */ + seek_data[5] = hh & 0xff; /* hH */ + + /* SEARCH */ + ccw[1].cmd = 0x31; + ccw[1].flags = CCW_FLAG_CC | CCW_FLAG_SLI; + ccw[1].count = 5; + ccw[1].addr = ADDR31(search_data); + + search_data[0] = cc >> 8; + search_data[1] = cc & 0xff; + search_data[2] = hh >> 8; + search_data[3] = hh & 0xff; + search_data[4] = r; + + /* TIC */ + ccw[2].cmd = 0x08; + ccw[2].flags = 0; + ccw[2].count = 0; + ccw[2].addr = ADDR31(&ccw[1]); + + /* READ DATA */ + ccw[3].cmd = 0x86; + ccw[3].flags = 0; + ccw[3].count = 4096; + ccw[3].addr = ADDR31(buf); + + /* + * issue IO + */ + ret = submit_io(dev, &ioop, CAN_SLEEP); + return ret; +} + +static struct device_type d3390 = { + .types = LIST_HEAD_INIT(d3390.types), + .reg = d3390_reg, + .interrupt = NULL, + .enable = NULL, + .snprintf = d3390_snprintf, + + .read = d3390_read, + + .type = 0x3390, + .all_models = 1, +}; + +/******************************************************************************/ + +static int d9336_snprintf(struct device *dev, char* buf, int len) +{ + return snprintf(buf, len, "%10d BLK ", dev->fba.blks); +} + +static int d9336_reg(struct device *dev) +{ + struct io_op ioop; + struct ccw ccw; + int ret; + u8 buf[64]; + + switch(dev->model) { + case 0x00: /* 9336-10 */ + case 0x10: /* 9336-20 */ + break; + default: + return -ENOENT; + } + + /* + * Set up IO op for Read Device Characteristics + */ + ioop.handler = NULL; + ioop.dtor = NULL; + + memset(&ioop.orb, 0, sizeof(struct orb)); + ioop.orb.lpm = 0xff; + ioop.orb.addr = ADDR31(&ccw); + ioop.orb.f = 1; + + memset(&ccw, 0, sizeof(struct ccw)); + ccw.cmd = 0x64; /* RDC */ + ccw.flags = CCW_FLAG_SLI; + ccw.count = 64; + ccw.addr = ADDR31(buf); + + /* + * issue RDC + */ + ret = submit_io(dev, &ioop, CAN_LOOP); + if (ret) + return ret; + + dev->fba.blk_size = (buf[4] << 8) | buf[5]; + dev->fba.bpg = (buf[6] << 24) | + (buf[7] << 16) | + (buf[8] << 8) | + buf[9]; + dev->fba.bpp = (buf[10] << 24) | + (buf[11] << 16) | + (buf[12] << 8) | + buf[13]; + dev->fba.blks= (buf[14] << 24) | + (buf[15] << 16) | + (buf[16] << 8) | + buf[17]; + + return 0; +} + +static struct device_type d9336 = { + .types = LIST_HEAD_INIT(d9336.types), + .reg = d9336_reg, + .interrupt = NULL, + .enable = NULL, + .snprintf = d9336_snprintf, + .type = 0x9336, + .all_models = 1, +}; + +int register_driver_dasd(void) +{ + int ret; + + ret = register_device_type(&d3390); + if (ret) + return ret; + + return register_device_type(&d9336); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/drivers/device.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,372 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <list.h> +#include <channel.h> +#include <io.h> +#include <slab.h> +#include <device.h> +#include <spinlock.h> +#include <sched.h> + +struct senseid_struct { + u8 __reserved; + u16 cu_type; + u8 cu_model; + u16 dev_type; + u8 dev_model; +} __attribute__((packed)); + +struct static_device { + u16 dev_num; + struct senseid_struct sense; +}; + +#define END_OF_STATIC_DEV_LIST 0xffff + +/* + * This defines staticly-configured devices - ugly but necessary for devices + * that fail to identify themseleves via Sense-ID + */ +static struct static_device static_device_list[] = { + { .dev_num = 0x0009, .sense = { .dev_type = 0x3215, .dev_model = 0 } }, + { .dev_num = END_OF_STATIC_DEV_LIST }, +}; + +/* + * We need this device temporarily because submit_io & friends assume that + * the device that's doing IO is on the device list. Unfortunately, that + * isn't the case during IO device scanning. We register this device type, + * and each device temporarily during the scan to make submit_io & friends + * happy. When we're done scanning, we unregister this type. + */ +static struct device_type __fake_dev_type = { + .types = LIST_HEAD_INIT(__fake_dev_type.types), + .reg = NULL, + .interrupt = NULL, + .snprintf = NULL, + .type = 0, + .model = 0, +}; + +static LIST_HEAD(device_types); +static spinlock_t dev_types_lock; + +static LIST_HEAD(devices); +static spinlock_t devs_lock; + +static void unregister_device_type(struct device_type *type) +{ + spin_lock(&dev_types_lock); + list_del(&type->types); + spin_unlock(&dev_types_lock); +} + +/** + * register_device_type - register a new device type/model + * @dev: device type to register + */ +int register_device_type(struct device_type *dev) +{ + struct device_type *entry; + + spin_lock(&dev_types_lock); + + list_for_each_entry(entry, &device_types, types) { + if (dev == entry || + (dev->type == entry->type && dev->model == entry->model)) { + spin_unlock(&dev_types_lock); + return -EEXIST; + } + } + + list_add_tail(&dev->types, &device_types); + + spin_unlock(&dev_types_lock); + + return 0; +} + +/** + * find_device_by_ccuu - find device struct by ccuu + * @ccuu: device ccuu to find + */ +struct device *find_device_by_ccuu(u16 ccuu) +{ + struct device *dev; + + spin_lock(&devs_lock); + + list_for_each_entry(dev, &devices, devices) { + if (dev->ccuu == ccuu) { + dev_get(dev); + spin_unlock(&devs_lock); + return dev; + } + } + + spin_unlock(&devs_lock); + + return ERR_PTR(-ENOENT); +} + +/** + * find_device_by_sch - find device struct by subchannel number + * @sch: device subchannel + */ +struct device *find_device_by_sch(u32 sch) +{ + struct device *dev; + + spin_lock(&devs_lock); + + list_for_each_entry(dev, &devices, devices) { + if (dev->sch == sch) { + dev_get(dev); + spin_unlock(&devs_lock); + return dev; + } + } + + spin_unlock(&devs_lock); + + return ERR_PTR(-ENOENT); +} + +/** + * find_device_by_type - find device struct by type/model + * @type: device type to find + * @model: device model to find + */ +struct device *find_device_by_type(u16 type, u8 model) +{ + struct device *dev; + + spin_lock(&devs_lock); + + list_for_each_entry(dev, &devices, devices) { + if (dev->type == type && + dev->model == model) { + dev_get(dev); + spin_unlock(&devs_lock); + return dev; + } + } + + spin_unlock(&devs_lock); + + return ERR_PTR(-ENOENT); +} + +/** + * __register_device - helper to register a device + * @dev: device to register + * @remove: remove the device from the list first + */ +static int __register_device(struct device *dev, int remove) +{ + struct device_type *type; + int err = 0; + + spin_double_lock(&devs_lock, &dev_types_lock); + + list_for_each_entry(type, &device_types, types) { + if (type->type == dev->type && + (type->all_models || + type->model == dev->model)) + goto found; + } + + err = -ENOENT; + type = NULL; + +found: + spin_double_unlock(&devs_lock, &dev_types_lock); + + atomic_set(&dev->refcnt, 1); + atomic_set(&dev->in_use, 0); + + dev->dev = type; + + if (type && type->reg) { + err = type->reg(dev); + + if (err) + dev->dev = NULL; + } + + spin_double_lock(&devs_lock, &dev_types_lock); + if (remove) + list_del(&dev->devices); + list_add_tail(&dev->devices, &devices); + spin_double_unlock(&devs_lock, &dev_types_lock); + + return err; +} + +static int do_sense_id(struct device *dev, u16 dev_num, struct senseid_struct *buf) +{ + struct io_op ioop; + struct ccw ccw; + int ret; + int idx; + struct static_device *sdev; + + /* + * Check static configuration; if device is found (by device + * number), use that information instead of issuing sense-id + */ + for(idx = 0; sdev = &static_device_list[idx], + sdev->dev_num != END_OF_STATIC_DEV_LIST; idx++) { + if (sdev->dev_num == dev_num) { + memcpy(buf, &sdev->sense, sizeof(struct senseid_struct)); + return 0; + } + } + + /* + * Set up IO op for Sense-ID + */ + ioop.handler = NULL; + ioop.dtor = NULL; + + memset(&ioop.orb, 0, sizeof(struct orb)); + ioop.orb.lpm = 0xff; + ioop.orb.addr = ADDR31(&ccw); + ioop.orb.f = 1; + + memset(&ccw, 0, sizeof(struct ccw)); + ccw.cmd = 0xe4; /* Sense-ID */ + ccw.flags = CCW_FLAG_SLI; + ccw.count = sizeof(struct senseid_struct); + ccw.addr = ADDR31(buf); + + /* + * issue SENSE-ID + */ + ret = submit_io(dev, &ioop, CAN_LOOP); + BUG_ON(ret); + + return ioop.err; +} + +/* + * Scan all subchannel ids, and register each device + */ +void scan_devices(void) +{ + struct schib schib; + struct device *dev = NULL; + struct senseid_struct buf; + u32 sch; + int ret; + + BUG_ON(register_device_type(&__fake_dev_type)); + + memset(&schib, 0, sizeof(struct schib)); + + /* + * For each possible subchannel id... + */ + for(sch = 0x10000; sch <= 0x1ffff; sch++) { + /* + * ...call store subchannel, to find out whether or not + * there is a device + */ + if (store_sch(sch, &schib)) + continue; + + if (!schib.pmcw.v) + continue; + + /* + * The following code tries to take the following steps: + * - alloc device struct + * - enable the subchannel + * - MSCH + * - issue SENSE-ID IO op & wait for completion + * - register device with apropriate subsystem + */ + + if (!dev) { + dev = malloc(sizeof(struct device), ZONE_NORMAL); + + /* + * if we failed to allocate memory, there's not much we can + * do + */ + BUG_ON(!dev); + + atomic_set(&dev->attention, 0); + INIT_LIST_HEAD(&dev->q_out); + dev->dev = &__fake_dev_type; + } + + schib.pmcw.e = 1; + + if (modify_sch(sch, &schib)) + continue; + + dev->sch = sch; + BUG_ON(__register_device(dev, 0)); + BUG_ON(dev->dev != &__fake_dev_type); + + /* + * Find out what the device is - whichever way is necessary + */ + ret = do_sense_id(dev, schib.pmcw.dev_num, &buf); + + if (ret) + continue; + + dev->type = buf.dev_type; + dev->model = buf.dev_model; + dev->ccuu = schib.pmcw.dev_num; + + /* __register_device will remove the fake entry! */ + if (__register_device(dev, 1)) { + /* + * error registering ... the device struct MUST NOT + * be freed as it has been added onto the devices + * list. All that needs to be done is to reset the + * enabled bit. + */ + schib.pmcw.e = 0; + + /* msch could fail, but it shouldn't be fatal */ + modify_sch(sch, &schib); + } + + /* to prevent a valid device struct from being free'd */ + dev = NULL; + } + + unregister_device_type(&__fake_dev_type); + + free(dev); +} + +void list_devices(struct console *con, void (*f)(struct console*, struct device*)) +{ + struct device *dev; + + spin_lock(&devs_lock); + + list_for_each_entry(dev, &devices, devices) { + dev_get(dev); + f(con, dev); + dev_put(dev); + } + + spin_unlock(&devs_lock); +} + +void register_drivers(void) +{ + register_driver_3215(); + register_driver_dasd(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/drivers/vdevice.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,85 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <slab.h> +#include <list.h> +#include <vdevice.h> + +static int __setup_vdev_ded(struct virt_sys *sys, + struct directory_vdev *dirdev, + struct virt_device *vdev) +{ + struct device *rdev; + + rdev = find_device_by_ccuu(dirdev->u.dedicate.rdev); + if (IS_ERR(rdev)) + return PTR_ERR(rdev); + + atomic_inc(&rdev->in_use); + + vdev->u.dedicate.rdev = rdev; + vdev->type = rdev->type; + vdev->model = rdev->model; + + return 0; +} + +int alloc_virt_dev(struct virt_sys *sys, struct directory_vdev *dirdev, + u32 sch) +{ + struct virt_device *vdev; + int ret = 0; + + vdev = malloc(sizeof(struct virt_device), ZONE_NORMAL); + if (!vdev) + return -ENOMEM; + + vdev->vtype = dirdev->type; + vdev->sch = sch; + vdev->pmcw.v = 1; + vdev->pmcw.dev_num = dirdev->vdev; + vdev->pmcw.lpm = 0x80; + vdev->pmcw.pim = 0x80; + vdev->pmcw.pom = 0xff; + vdev->pmcw.pam = 0x80; + + switch(dirdev->type) { + case VDEV_CONS: + vdev->type = 0x3215; + vdev->model = 0; + break; + case VDEV_DED: + ret = __setup_vdev_ded(sys, dirdev, vdev); + break; + case VDEV_SPOOL: + vdev->type = dirdev->u.spool.type; + vdev->model = dirdev->u.spool.model; + // FIXME: hook it up to the spooler + break; + case VDEV_MDISK: + vdev->type = 0x3390; + vdev->model = 3; + // FIXME: hook it up to mdisk driver + break; + case VDEV_LINK: + goto free; + case VDEV_INVAL: + goto out; + } + + list_add_tail(&vdev->devices, &sys->virt_devs); + + return ret; + +free: + free(vdev); + return 0; + +out: + free(vdev); + return -EINVAL; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/fs/Makefile Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,1 @@ +objs-fs := bdev.o edf.o
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/fs/bdev.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,17 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <device.h> +#include <bdev.h> + +int bdev_read_block(struct device *dev, void *buf, int lba) +{ + if (!dev->dev->read) + return -EINVAL; + + return dev->dev->read(dev, buf, lba); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/fs/edf.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,178 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <mutex.h> +#include <buddy.h> +#include <slab.h> +#include <device.h> +#include <bdev.h> +#include <ebcdic.h> +#include <edf.h> + +struct fs *edf_mount(struct device *dev) +{ + struct page *page; + void *tmp; + struct fs *fs; + long ret; + + page = alloc_pages(0, ZONE_NORMAL); + if (!page) + return ERR_PTR(-ENOMEM); + tmp = page_to_addr(page); + + ret = -ENOMEM; + fs = malloc(sizeof(struct fs), ZONE_NORMAL); + if (!fs) + goto out_free; + + /* First, read & verify the label */ + ret = bdev_read_block(dev, tmp, EDF_LABEL_BLOCK_NO); + if (ret) + goto out_free; + + mutex_init(&fs->lock); + INIT_LIST_HEAD(&fs->files); + fs->dev = dev; + fs->tmp_buf = tmp; + + memcpy(&fs->ADT, tmp, sizeof(struct ADT)); + + ret = -EINVAL; + if ((fs->ADT.ADTIDENT != __ADTIDENT) || + (fs->ADT.ADTDBSIZ != EDF_SUPPORTED_BLOCK_SIZE) || + (fs->ADT.ADTOFFST != 0) || + (fs->ADT.ADTFSTSZ != sizeof(struct FST))) + goto out_free; + + return fs; + +out_free: + free(fs); + free_pages(tmp, 0); + return ERR_PTR(ret); +} + +extern struct console *oper_con; +struct file *edf_lookup(struct fs *fs, char *fn, char *ft) +{ + char __fn[8]; + char __ft[8]; + struct page *page; + struct file *file; + struct file *tmpf; + struct FST *fst; + long ret; + int found; + int i; + + file = malloc(sizeof(struct file), ZONE_NORMAL); + if (!file) + return ERR_PTR(-ENOMEM); + + file->fs = fs; + file->buf = NULL; + + memcpy(__fn, fn, 8); + memcpy(__ft, ft, 8); + ascii2ebcdic((u8 *) __fn, 8); + ascii2ebcdic((u8 *) __ft, 8); + + mutex_lock(&fs->lock); + + /* first, check the cache */ + list_for_each_entry(tmpf, &fs->files, files) { + if (!memcmp((char*) tmpf->FST.FSTFNAME, __fn, 8) && + !memcmp((char*) tmpf->FST.FSTFTYPE, __ft, 8)) { + mutex_unlock(&fs->lock); + free(file); + return tmpf; + } + } + + page = alloc_pages(0, ZONE_NORMAL); + if (!page) { + ret = -ENOMEM; + goto out_unlock; + } + file->buf = page_to_addr(page); + + /* oh well, must do it the hard way ... read from disk */ + ret = bdev_read_block(fs->dev, fs->tmp_buf, fs->ADT.ADTDOP); + if (ret) + goto out_unlock; + + fst = fs->tmp_buf; + + for(i=0,found=0; i<fs->ADT.ADTNFST; i++) { + if ((!memcmp(fst[i].FSTFNAME, __fn, 8)) && + (!memcmp(fst[i].FSTFTYPE, __ft, 8))) { + memcpy(&file->FST, &fst[i], sizeof(struct FST)); + found = 1; + break; + } + } + + if (!found) { + ret = -ENOENT; + goto out_unlock; + } + + mutex_init(&file->lock); + list_add_tail(&file->files, &fs->files); + + mutex_unlock(&fs->lock); + + return file; + +out_unlock: + if (file && file->buf) + free_pages(file->buf, 0); + mutex_unlock(&fs->lock); + free(file); + return ERR_PTR(ret); +} + +int edf_read_rec(struct file *file, char *buf, u32 recno) +{ + struct fs *fs = file->fs; + u32 fop, lrecl; + int ret; + + if (file->FST.FSTNLVL != 0 || + file->FST.FSTPTRSZ != 4 || + file->FST.FSTLRECL > fs->ADT.ADTDBSIZ || + file->FST.FSTRECFM != FSTDFIX) + return -EINVAL; + + mutex_lock(&file->lock); + + fop = file->FST.FSTFOP; + lrecl = file->FST.FSTLRECL; + + ret = bdev_read_block(fs->dev, file->buf, fop); + if (ret) + goto out; + + memcpy(buf, file->buf + (recno * lrecl), lrecl); + +out: + mutex_unlock(&file->lock); + + return ret; +} + +void edf_file_free(struct file *file) +{ + struct fs *fs = file->fs; + + mutex_lock(&fs->lock); + list_del(&file->files); + mutex_unlock(&fs->lock); + + free(file); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/hvf.directory Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,26 @@ +USER OPERATOR A + MACHINE ESA 1 + STORAGE 17M + CONSOLE 0009 3215 + SPOOL 000C 3505 READER + SPOOL 000D 3525 PUNCH + SPOOL 000E 1403 PRINT + MDISK 0191 3390 15 100 0192 + +USER JEFFPC A + MACHINE ESA 1 + STORAGE 64M + CONSOLE 0009 3215 + SPOOL 000C 3505 READER + SPOOL 000D 3525 PUNCH + SPOOL 000E 1403 PRINT + MDISK 0190 3390 15 100 0192 + +USER OBIWAN G + MACHINE ESA 1 + STORAGE 2M + CONSOLE 0009 3215 + SPOOL 000C 3505 READER + SPOOL 000D 3525 PUNCH + SPOOL 000E 1403 PRINT + MDISK 0193 3390 15 100 0192
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/atomic.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,203 @@ +/* + * Based on atomic.h from Linux Kernel + */ + +#ifndef __ARCH_S390_ATOMIC__ +#define __ARCH_S390_ATOMIC__ + +/* + * include/asm-s390/atomic.h + * + * S390 version + * Copyright (C) 1999-2005 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + * Denis Joseph Barrow, + * Arnd Bergmann (arndb@de.ibm.com) + * + * Derived from "include/asm-i386/bitops.h" + * Copyright (C) 1992, Linus Torvalds + * + */ + +/* + * Atomic operations that C can't guarantee us. Useful for + * resource counting etc.. + * S390 uses 'Compare And Swap' for atomicity in SMP enviroment + */ + +typedef struct { + volatile int counter; +} __attribute__ ((aligned (4))) atomic_t; +#define ATOMIC_INIT(i) { (i) } + +#define __CS_LOOP(ptr, op_val, op_string) ({ \ + typeof(ptr->counter) old_val, new_val; \ + asm volatile( \ + " l %0,%2\n" \ + "0: lr %1,%0\n" \ + op_string " %1,%3\n" \ + " cs %0,%1,%2\n" \ + " jl 0b" \ + : "=&d" (old_val), "=&d" (new_val), \ + "=Q" (((atomic_t *)(ptr))->counter) \ + : "d" (op_val), "Q" (((atomic_t *)(ptr))->counter) \ + : "cc", "memory"); \ + new_val; \ +}) + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) (((v)->counter) = (i)) + +static __inline__ int atomic_add_return(int i, atomic_t * v) +{ + return __CS_LOOP(v, i, "ar"); +} +#define atomic_add(_i, _v) atomic_add_return(_i, _v) +#define atomic_add_negative(_i, _v) (atomic_add_return(_i, _v) < 0) +#define atomic_inc(_v) atomic_add_return(1, _v) +#define atomic_inc_return(_v) atomic_add_return(1, _v) +#define atomic_inc_and_test(_v) (atomic_add_return(1, _v) == 0) + +static __inline__ int atomic_sub_return(int i, atomic_t * v) +{ + return __CS_LOOP(v, i, "sr"); +} +#define atomic_sub(_i, _v) atomic_sub_return(_i, _v) +#define atomic_sub_and_test(_i, _v) (atomic_sub_return(_i, _v) == 0) +#define atomic_dec(_v) atomic_sub_return(1, _v) +#define atomic_dec_return(_v) atomic_sub_return(1, _v) +#define atomic_dec_and_test(_v) (atomic_sub_return(1, _v) == 0) + +static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t * v) +{ + __CS_LOOP(v, ~mask, "nr"); +} + +static __inline__ void atomic_set_mask(unsigned long mask, atomic_t * v) +{ + __CS_LOOP(v, mask, "or"); +} + +#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) + +static __inline__ int atomic_cmpxchg(atomic_t *v, int old, int new) +{ + asm volatile( + " cs %0,%2,%1" + : "+d" (old), "=Q" (v->counter) + : "d" (new), "Q" (v->counter) + : "cc", "memory"); + return old; +} + +static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) +{ + int c, old; + c = atomic_read(v); + for (;;) { + if (unlikely(c == u)) + break; + old = atomic_cmpxchg(v, c, c + a); + if (likely(old == c)) + break; + c = old; + } + return c != u; +} + +#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) + +#undef __CS_LOOP + +typedef struct { + volatile long long counter; +} __attribute__ ((aligned (8))) atomic64_t; +#define ATOMIC64_INIT(i) { (i) } + +#define __CSG_LOOP(ptr, op_val, op_string) ({ \ + typeof(ptr->counter) old_val, new_val; \ + asm volatile( \ + " lg %0,%2\n" \ + "0: lgr %1,%0\n" \ + op_string " %1,%3\n" \ + " csg %0,%1,%2\n" \ + " jl 0b" \ + : "=&d" (old_val), "=&d" (new_val), \ + "=Q" (((atomic_t *)(ptr))->counter) \ + : "d" (op_val), "Q" (((atomic_t *)(ptr))->counter) \ + : "cc", "memory" ); \ + new_val; \ +}) + +#define atomic64_read(v) ((v)->counter) +#define atomic64_set(v,i) (((v)->counter) = (i)) + +static __inline__ long long atomic64_add_return(long long i, atomic64_t * v) +{ + return __CSG_LOOP(v, i, "agr"); +} +#define atomic64_add(_i, _v) atomic64_add_return(_i, _v) +#define atomic64_add_negative(_i, _v) (atomic64_add_return(_i, _v) < 0) +#define atomic64_inc(_v) atomic64_add_return(1, _v) +#define atomic64_inc_return(_v) atomic64_add_return(1, _v) +#define atomic64_inc_and_test(_v) (atomic64_add_return(1, _v) == 0) + +static __inline__ long long atomic64_sub_return(long long i, atomic64_t * v) +{ + return __CSG_LOOP(v, i, "sgr"); +} +#define atomic64_sub(_i, _v) atomic64_sub_return(_i, _v) +#define atomic64_sub_and_test(_i, _v) (atomic64_sub_return(_i, _v) == 0) +#define atomic64_dec(_v) atomic64_sub_return(1, _v) +#define atomic64_dec_return(_v) atomic64_sub_return(1, _v) +#define atomic64_dec_and_test(_v) (atomic64_sub_return(1, _v) == 0) + +static __inline__ void atomic64_clear_mask(unsigned long mask, atomic64_t * v) +{ + __CSG_LOOP(v, ~mask, "ngr"); +} + +static __inline__ void atomic64_set_mask(unsigned long mask, atomic64_t * v) +{ + __CSG_LOOP(v, mask, "ogr"); +} + +#define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) + +static __inline__ long long atomic64_cmpxchg(atomic64_t *v, + long long old, long long new) +{ + asm volatile( + " csg %0,%2,%1" + : "+d" (old), "=Q" (v->counter) + : "d" (new), "Q" (v->counter) + : "cc", "memory"); + return old; +} + +static __inline__ int atomic64_add_unless(atomic64_t *v, + long long a, long long u) +{ + long long c, old; + c = atomic64_read(v); + for (;;) { + if (unlikely(c == u)) + break; + old = atomic64_cmpxchg(v, c, c + a); + if (likely(old == c)) + break; + c = old; + } + return c != u; +} + +#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) + +#undef __CSG_LOOP + +#define smp_mb__before_atomic_dec() smp_mb() +#define smp_mb__after_atomic_dec() smp_mb() +#define smp_mb__before_atomic_inc() smp_mb() +#define smp_mb__after_atomic_inc() smp_mb() + +#endif /* __ARCH_S390_ATOMIC__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/bdev.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,13 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __BDEV_H +#define __BDEV_H + +extern int bdev_read_block(struct device *dev, void *buf, int lba); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/buddy.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,17 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __BUDDY_H +#define __BUDDY_H + +#include <page.h> + +extern void init_buddy_alloc(u64 start); +extern struct page *alloc_pages(int order, int type); +extern void free_pages(void *ptr, int order); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/channel.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,309 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __CHANNEL_H +#define __CHANNEL_H + +/* + * We only care about format-1 CCWs + */ +struct ccw { + u8 cmd; /* Command code */ + u8 flags; /* Flags */ + u16 count; /* Count */ + u32 addr; /* Data Address */ +} __attribute__((packed,aligned(8))); + +struct ccw0 { + u8 cmd; /* Command code */ + u8 addr_hi; /* Data Address (bits 8-15) */ + u16 addr_lo; /* Data Address (bits 16-31) */ + u8 flags; /* Flags */ + u8 _res0; + u16 count; /* Count */ +} __attribute__((packed,aligned(8))); + +#define CCW_CMD_IPL_READ 0x02 +#define CCW_CMD_NOP 0x03 +#define CCW_CMD_BASIC_SENSE 0x04 +#define CCW_CMD_SENSE_ID 0xe4 +#define CCW_CMD_TIC 0x08 + +#define CCW_FLAG_CD 0x80 /* Chain-Data */ +#define CCW_FLAG_CC 0x40 /* Chain-Command */ +#define CCW_FLAG_SLI 0x20 /* Suppress-Length-Indication */ +#define CCW_FLAG_SKP 0x10 /* Skip */ +#define CCW_FLAG_PCI 0x08 /* Program-Controlled-Interruption */ +#define CCW_FLAG_IDA 0x04 /* Indirect-Data-Address */ +#define CCW_FLAG_S 0x02 /* Suspend */ +#define CCW_FLAG_MIDA 0x01 /* Modified-Indirect-Data-Address */ + +/* + * ORB + */ +struct orb { + /* word 0 */ + u32 param; /* Interruption Parameter */ + + /* word 1 */ + u8 key:4, /* Subchannel Key */ + s:1, /* Suspend */ + c:1, /* Streaming-Mode Control */ + m:1, /* Modification Control */ + y:1; /* Synchronization Control */ + u8 f:1, /* Format Control */ + p:1, /* Prefetch Control */ + i:1, /* Initial-Status-Interruption Control */ + a:1, /* Address-Limit-Checking control */ + u:1, /* Suppress-Suspend-Interruption Control */ + __zero1:1, + h:1, /* Format-2-IDAW Control */ + t:1; /* 2K-IDAW Control */ + u8 lpm; /* Logical-Path Mask */ + u8 l:1, /* Incorrect-Length-Suppression Mode */ + d:1, /* Modified-CCW-Indirect-Data-Addressing Control */ + __zero2:5, + x:1; /* ORB-Extension Control */ + + /* word 2 */ + u32 addr; /* Channel-Program Address */ + + /* word 3 */ + u8 css_prio; /* Channel-Subsystem Priority */ + u8 __reserved1; + u8 cu_prio; /* Control-Unit Priority */ + u8 __reserved2; + + /* word 4 - 7 */ + u32 __reserved3; + u32 __reserved4; + u32 __reserved5; + u32 __reserved6; +} __attribute__((packed,aligned(4))); + +enum SCSW_FC { + FC_CLEAR = 0x10, + FC_HALT = 0x20, + FC_START = 0x40, +}; + +enum SCSW_SC { + SC_STATUS = 0x01, + SC_SECONDARY = 0x02, + SC_PRIMARY = 0x04, + SC_INTERMED = 0x08, + SC_ALERT = 0x10, +}; + +struct scsw { + /* word 0 */ + u16 key:4, /* Subchannel key */ + s:1, /* Suspend control */ + l:1, /* ESW format */ + cc:2, /* Deferred condition code */ + f:1, /* Format */ + p:1, /* Prefetch */ + i:1, /* Initial-status interruption control */ + a:1, /* Address-limit-checking control */ + u:1, /* Supress-suspended interruption */ + z:1, /* Zero condition code */ + e:1, /* Extended control */ + n:1; /* Path no operational */ + u16 __zero:1, + fc:3, /* Function control */ + ac:8, /* Activity control */ + sc:4; /* Status control */ + + /* word 1 */ + u32 addr; /* CCW Address */ + + /* word 2 */ + u8 dev_status; /* Device status */ + u8 sch_status; /* Subchannel status */ + u16 count; /* Count */ +} __attribute__((packed)); + +/* needed by IRB */ +struct irb_ext_status { + /* TODO: not implemented */ + u32 w0, w1, w2, w3, w4; +} __attribute__((packed)); + +/* needed by IRB */ +struct irb_ext_control { + /* TODO: not implemented */ + u32 w0, w1, w2, w3, w4, w5, w6, w7; +} __attribute__((packed)); + +/* needed by IRB */ +struct irb_ext_measurement { + /* TODO: not implemented */ + u32 w0, w1, w2, w3, w4, w5, w6, w7; +} __attribute__((packed)); + +struct irb { + struct scsw scsw; /* Subchannel-Status */ + struct irb_ext_status ext_status; /* Extended-Status */ + struct irb_ext_control ext_control; /* Extended-Control */ + struct irb_ext_measurement ext_measure; /* Extended-Measurement */ +} __attribute__((packed,aligned(4))); + +/* Path Management Control Word */ +struct pmcw { + /* word 0 */ + u32 interrupt_param; /* Interruption Parameter */ + + /* word 1*/ + u8 __zero1:2, + isc:3, /* I/O-Interruption-Subclass Code */ + __zero2:3; + u8 e:1, /* Enabled */ + lm:2, /* Limit Mode */ + mm:2, /* Measurement-Mode Enable */ + d:1, /* Multipath Mode */ + t:1, /* Timing Facility */ + v:1; /* Device Number Valid */ + u16 dev_num; /* Device Number */ + + /* word 2 */ + u8 lpm; /* Logical-Path Mask */ + u8 pnom; /* Path-Not-Operational Mask */ + u8 lpum; /* Last-Path-Used Mask */ + u8 pim; /* Path-Installed Mask */ + + /* word 3 */ + u16 mbi; /* Measurement-Block Index */ + u8 pom; /* Path-Operational Mask */ + u8 pam; /* Path-Available Mask */ + + /* word 4 & 5 */ + u8 chpid[8]; /* Channel-Path Identifiers */ + + /* word 6 */ + u16 __zero3; + u16 __zero4:13, + f:1, /* Measurement Block Format Control */ + x:1, /* Extended Measurement Word Mode Enable */ + s:1; /* Concurrent Sense */ +}; + +/* needed by schib */ +struct schib_measurement_block { + /* TODO: not implemented */ + u32 w0, w1; +}; + +struct schib { + struct pmcw pmcw; /* Path Management Control Word */ + struct scsw scsw; /* Subchannel Status Word */ + union { + struct schib_measurement_block measure_block; + }; + u32 model_dep_area; +} __attribute__((packed,aligned(4))); + +static inline int store_sch(u32 sch, struct schib *schib) +{ + int cc; + + asm volatile( + "lr %%r1,%2\n" + "stsch %1\n" + "ipm %0\n" + "srl %0,28\n" + : /* output */ + "=d" (cc), + "=Q" (*schib) + : /* input */ + "d" (sch) + : /* clobbered */ + "cc", "r1", "memory" + ); + + if (cc == 3) + return -EINVAL; + return 0; +} + +static inline int modify_sch(u32 sch, struct schib *schib) +{ + int cc; + + asm volatile( + "lr %%r1,%1\n" + "msch 0(%2)\n" + "ipm %0\n" + "srl %0,28\n" + : /* output */ + "=d" (cc) + : /* input */ + "d" (sch), + "a" (schib) + : /* clobbered */ + "cc", "r1" + ); + + if (cc == 1 || cc == 2) + return -EBUSY; + if (cc == 3) + return -EINVAL; + return 0; +} + +static inline int start_sch(u32 sch, struct orb *orb) +{ + int cc; + + asm volatile( + " lr %%r1,%1\n" + " ssch 0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + : /* output */ + "=d" (cc) + : /* input */ + "d" (sch), + "a" (orb) + : /* clobbered */ + "cc", "r1" + ); + + if (cc == 1 || cc == 2) + return -EBUSY; + if (cc == 3) + return -EINVAL; + + return 0; +} + +static inline int test_sch(u32 sch, struct irb *irb) +{ + int cc; + + asm volatile( + " lr %%r1,%1\n" + " tsch 0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + : /* output */ + "=d" (cc) + : /* input */ + "d" (sch), + "a" (irb) + : /* clobbered */ + "cc", "r1" + ); + + if (cc == 3) + return -EINVAL; + + return 0; +} + +extern void scan_devices(void); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/compiler.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,17 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __COMPILER_H +#define __COMPILER_H + +/* + * For compatibility with some Linux kernel code + */ +#define likely(x) (x) +#define unlikely(x) (x) + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/config.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,21 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +/* + * Base address within a guest's address space; used as the base address for + * the IPL helper code. + * + * NOTE: It must be >= 16M, but <2G + */ +#define GUEST_IPL_BASE (16ULL * 1024ULL * 1024ULL) + +#define OPER_CONSOLE_CCUU 0x0009 + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/console.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,57 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __CONSOLE_H +#define __CONSOLE_H + +#include <device.h> +#include <io.h> +#include <spinlock.h> + +/* line allocation size */ +#define CON_LINE_ALLOC_SIZE 256 + +/* maximum line length */ +#define CON_MAX_LINE_LEN (CON_LINE_ALLOC_SIZE - sizeof(struct console_line)) + +/* maximum number of free lines to keep around */ +#define CON_MAX_FREE_LINES 32 + +/* number of lines of console text to flush at a time */ +#define CON_MAX_FLUSH_LINES 32 + +/* line state */ +#define CON_STATE_FREE 0 +#define CON_STATE_PENDING 1 +#define CON_STATE_IO 2 + +struct console_line { + struct list_head lines; + u16 len; + u16 state; + u8 buf[0]; +}; + +struct console { + struct list_head consoles; + struct virt_sys *sys; + struct device *dev; + spinlock_t lock; + struct list_head write_lines; + struct list_head read_lines; +}; + +extern int console_interrupt(struct device *dev, struct irb *irb); +extern struct console* start_oper_console(void); +extern void* console_enable(struct device *dev); +extern int con_read_pending(struct console *con); +extern int con_read(struct console *con, u8 *buf, int size); +extern int con_write(struct console *con, u8 *buf, int len); +extern void for_each_console(void (*f)(struct console *con)); +extern struct console* find_console(struct device *dev); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/cpu.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __CPU_H +#define __CPU_H + +static inline u64 getcpuid() +{ + u64 cpuid = ~0; + + asm("stidp 0(%1)\n" + : /* output */ + "=m" (cpuid) + : /* input */ + "a" (&cpuid) + ); + + return cpuid; +} + +static inline u16 getcpuaddr() +{ + u16 cpuaddr = ~0; + + asm("stap 0(%1)\n" + : /* output */ + "=m" (cpuaddr) + : /* input */ + "a" (&cpuaddr) + ); + + return cpuaddr; +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/dat.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,143 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __DAT_H +#define __DAT_H + +struct address_space { + struct dat_rte *region_table; + struct dat_ste *segment_table; +}; + +/* region/segment-table destination */ +struct dat_td { + u64 origin:52, /* region/segment table origin */ + __reserved0:2, + g:1, /* subspace-group control */ + p:1, /* private-space control */ + s:1, /* storage-alteration-event ctl */ + x:1, /* space-switch-event control */ + r:1, /* real-space control */ + __reserved1:1, + dt:2, /* designation-type control */ + tl:2; /* table length */ +} __attribute__((packed)); + +#define DAT_TD_DT_RFT 3 /* region-first */ +#define DAT_TD_DT_RST 2 /* region-second */ +#define DAT_TD_DT_RTT 1 /* region-third */ +#define DAT_TD_DT_ST 0 /* segment */ + +/* region-table entries (first, second, and third) */ +struct dat_rte { + u64 origin:52, /* next-level-table origin */ + __reserved0:4, + tf:2, /* table offset (next lower tbl) */ + i:1, /* region invalid */ + __reserved1:1, + tt:2, /* table-type bits (current tbl) */ + tl:2; /* table length (next lower tbl) */ +} __attribute__((packed)); + +/* + * Constants for struct rte + */ +#define DAT_RTE_TT_RFT 3 /* region-first */ +#define DAT_RTE_TT_RST 2 /* region-second */ +#define DAT_RTE_TT_RTT 1 /* region-third */ + +#define ADDR_TO_RTE_ORIGIN(a) ((a) >> 12) +#define RTE_ORIGIN_TO_ADDR(o) ((void*)(((u64)(o)) << 12)) + +/* segment-table entries */ +struct dat_ste { + u64 origin:53, /* page-table origin */ + __reserved0:1, + p:1, /* page-protection bit */ + __reserved1:3, + i:1, /* segment-invalid bit */ + c:1, /* common-segment bit */ + tt:2, /* table-type bits */ + __reserved2:2; +} __attribute__((packed)); + +#define DAT_STE_TT_ST 0 /* segment-table */ + +#define ADDR_TO_STE_ORIGIN(a) ((a) >> 11) +#define STE_ORIGIN_TO_ADDR(o) ((void*)(((u64)(o)) << 11)) + +/* page-table entries */ +struct dat_pte { + u64 pfra:52, /* page-frame real address */ + __zero0:1, + i:1, /* page-invalid bit */ + p:1, /* page-protection bit */ + __zero1:1, + __reserved:8; +} __attribute__((packed)); + +#define DAT_RX(addr) (((u64)(addr)) >> 31) +#define DAT_SX(addr) ((((u64)(addr)) >> 20) & 0x7ff) +#define DAT_PX(addr) ((((u64)(addr)) >> 12) & 0xff) +#define DAT_BX(addr) (((u64)(addr))& 0xfff) + +extern int dat_insert_page(struct address_space *as, u64 phy, u64 virt); +extern void setup_dat(void); +extern void load_as(struct address_space *as); + +extern int virt2phy(struct address_space *as, u64 virt, u64 *phy); + +static inline void store_pasce(u64 *pasce) +{ + asm volatile( + " stctg 1,1,0(%0)\n" + : /* output */ + : /* input */ + "a" (pasce) + ); +} + +static inline void load_pasce(u64 pasce) +{ + if (!pasce) + return; + + asm volatile( + " lctlg 1,1,%0\n" + : /* output */ + : /* input */ + "m" (pasce) + ); +} + +/* get host real address from guest real, using the currently loaded ASCE */ +static inline int virt2phy_current(u64 virt, u64 *phy) +{ + u64 result; + int cc; + + asm volatile( + " lrag %0,0(%%r0,%2)\n" + " ipm %1\n" + " srl %1,28\n" + : /* output */ + "=d" (result), + "=d" (cc) + : /* input */ + "a" (virt) + : /* clobber */ + "cc" + ); + + if (cc != 0) + return -EFAULT; + + *phy = result; + return 0; +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/device.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,98 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __DEVICE_H +#define __DEVICE_H + +#include <atomic.h> +#include <spinlock.h> +#include <list.h> + +struct device; +struct irb; + +struct device_type { + struct list_head types; + int (*reg)(struct device *dev); + int (*interrupt)(struct device *dev, struct irb *irb); + void* (*enable)(struct device *dev); + int (*snprintf)(struct device *dev, char *buf, int len); + + /* the following ops are for the bdev wrapper layer */ + int (*read)(struct device *dev, u8 *buf, int len); + + u16 type; + u8 model; + u8 all_models; +}; + +struct device { + struct list_head devices; + u32 sch; /* subchannel id */ + u16 type; /* 3330, 3215, ... */ + u8 model; + u16 ccuu; /* device number */ + struct device_type *dev; + + spinlock_t q_lock; + struct io_op *q_cur; + struct list_head q_out; + atomic_t attention; + + atomic_t in_use; /* is the device in use by someone? */ + + atomic_t refcnt; /* internal reference counter */ + + union { + struct { + u16 cyls; /* cylinders */ + u16 tracks; /* tracks per cylinder */ + u16 len; /* track length */ + u16 recs; /* number of records */ + u8 sectors; /* # sectors per track */ + u8 formula; /* capacity formula */ + u16 f1, /* factor f1 */ + f2, /* factor f2 */ + f3, /* factor f3 */ + f4, /* factor f4 */ + f5; /* factor f5 */ + } eckd; + struct { + u16 blk_size; /* block size */ + u32 bpg; /* blocks per cyclical group */ + u32 bpp; /* blocks per access possition */ + u32 blks; /* blocks */ + } fba; + }; +}; + +extern struct device *find_device_by_type(u16 type, u8 model); +extern struct device *find_device_by_ccuu(u16 ccuu); +extern struct device *find_device_by_sch(u32 sch); +extern int register_device_type(struct device_type *dev); +extern void scan_devices(void); +extern void list_devices(struct console *con, + void (*f)(struct console*, struct device*)); +extern void register_drivers(void); + +static inline void dev_get(struct device *dev) +{ + BUG_ON(atomic_read(&dev->refcnt) < 1); + atomic_inc(&dev->refcnt); +} + +static inline void dev_put(struct device *dev) +{ + atomic_dec(&dev->refcnt); + BUG_ON(atomic_read(&dev->refcnt) < 1); +} + +/* device specific register functions */ +extern int register_driver_3215(void); +extern int register_driver_dasd(void); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/directory.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,69 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __DIRECTORY_H +#define __DIRECTORY_H + +#include <console.h> + +enum directory_vdevtype { + VDEV_INVAL = 0, /* invalid */ + VDEV_CONS, /* a console */ + VDEV_DED, /* dedicated real device */ + VDEV_SPOOL, /* backed by the spool */ + VDEV_MDISK, /* a minidisk */ + VDEV_LINK, /* a link to another user's device */ +}; + +struct directory_vdev { + enum directory_vdevtype type; /* device type */ + u16 vdev; /* virtual dev # */ + + union { + /* VDEV_CONS */ + struct { + } console; + + /* VDEV_DED */ + struct { + u16 rdev; /* real device # */ + } dedicate; + + /* VDEV_SPOOL */ + struct { + u16 type; + u8 model; + } spool; + + /* VDEV_MDISK */ + struct { + u16 cyloff; /* first cylinder # */ + u16 cylcnt; /* cylinder count */ + u16 rdev; /* real DASD containing the mdisk */ + } mdisk; + + /* VDEV_LINK */ + struct { + } link; + } u; +}; + +struct user { + char *userid; + struct task *task; + + /* VM configuration */ + u64 storage_size; + + struct directory_vdev *devices; + + u8 auth; +}; + +extern struct user *find_user_by_id(char *userid); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/disassm.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,76 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __DISASSM_H +#define __DISASSM_H + +enum inst_fmt { + IF_INV = 0, + IF_VAR, + IF_E, + IF_I, + IF_RI1, + IF_RI2, + IF_RIE, + IF_RIL1, + IF_RIL2, + IF_RIS, + IF_RR, + IF_RR_MASK, + IF_RRE, + IF_RRF1, + IF_RRF2, + IF_RRF3, + IF_RRR, + IF_RRS, + IF_RS1, + IF_RS2, + IF_RSI, + IF_RSL, + IF_RSY1, + IF_RSY2, + IF_RX, + IF_RX_MASK, + IF_RXE, + IF_RXF, + IF_RXY, + IF_S, + IF_SI, + IF_SIL, + IF_SIY, + IF_SS1, + IF_SS2, + IF_SS3, + IF_SS4, + IF_SS5, + IF_SSE, + IF_SSF, + IF_DIAG, +}; + +struct disassm_instruction { + union { + char *name; /* instruction name; inst only */ + + void *ptr; /* next level table; table only */ + } u; + + /* all */ + char fmt; /* instruction format */ + + /* table only */ + char len; /* table len */ + char loc; /* sub-opcode location offset in bits */ +}; + +#define DA_INST(idx,ifmt,iname) [idx] = { .fmt = IF_##ifmt, .u.name = #iname, } +#define DA_INST_TBL(idx,itbl,ilen,iloc) [idx] = { .fmt = IF_VAR, .u.ptr = (itbl), \ + .len = (ilen), .loc = (iloc), } + +extern int disassm(u8 *bytes, char *buf, int buflen); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/ebcdic.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,41 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __EBCDIC_H +#define __EBCDIC_H + +extern u8 ascii2ebcdic_table[256]; +extern u8 ebcdic2ascii_table[256]; + +/* + * Generic translate buffer function. + */ +static inline void __translate(u8 *buf, int len, const u8 *table) +{ + asm volatile( + " sgr %%r0,%%r0\n" /* test byte = 0 */ + " la %%r2,0(%0)\n" /* buffer */ + " lgr %%r3,%2\n" /* length */ + " la %%r4,0(%1)\n" /* table */ + "0: tre %%r2,%%r4\n" + " brc 1,0b\n" + : /* output */ + : /* input */ + "a" (buf), + "a" (table), + "d" (len) + : /* clobbered */ + "cc", "r0", "r2", "r3", "r4" + ); +} + +#define ascii2ebcdic(buf, len) \ + __translate((buf), (len), ascii2ebcdic_table) +#define ebcdic2ascii(buf, len) \ + __translate((buf), (len), ebcdic2ascii_table) + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/edf.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,107 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __EDF_H +#define __EDF_H + +#include <mutex.h> +#include <device.h> + +struct ADT { + u32 ADTIDENT; /* VOL START / LABEL IDENTIFIER */ +#define __ADTIDENT 0xC3D4E2F1 /* 'CMS1' in EBCDIC */ + u8 ADTID[6]; /* VOL START / VOL IDENTIFIER */ + u8 ADTVER[2]; /* VERSION LEVEL */ + u32 ADTDBSIZ; /* DISK BLOCK SIZE */ + u32 ADTDOP; /* DISK ORIGIN POINTER */ + u32 ADTCYL; /* NUM OF FORMATTED CYL ON DISK */ + u32 ADTMCYL; /* MAX NUM FORMATTED CYL ON DISK */ + u32 ADTNUM; /* Number of Blocks on disk */ + u32 ADTUSED; /* Number of Blocks used */ + u32 ADTFSTSZ; /* SIZE OF FST */ + u32 ADTNFST; /* NUMBER OF FST'S PER BLOCK */ + u8 ADTDCRED[6]; /* DISK CREATION DATE (YYMMDDHHMMSS) */ + u8 ADTFLGL; /* LABEL FLAG BYTE (ADTFLGL) */ +#define ADTCNTRY 0x01 /* Century for disk creation date (0=19, 1=20), + * corresponds to ADTDCRED. */ + u8 reserved[1]; + u32 ADTOFFST; /* DISK OFFSET WHEN RESERVED */ + u32 ADTAMNB; /* ALLOC MAP BLOCK WITH NEXT HOLE */ + u32 ADTAMND; /* DISP INTO HBLK DATA OF NEXT HOLE */ + u32 ADTAMUP; /* DISP INTO USER PART OF ALLOC MAP */ + u32 ADTOFCNT; /* Count of SFS open files for this ADT */ + u8 ADTSFNAM[8]; /* NAME OF SHARED SEGMENT */ +}; + +struct FST { + u8 FSTFNAME[8]; /* filename */ + u8 FSTFTYPE[8]; /* filetype */ + u8 FSTDATEW[2]; /* DATE LAST WRITTEN - MMDD */ + u8 FSTTIMEW[2]; /* TIME LAST WRITTEN - HHMM */ + u16 FSTWRPNT; /* WRITE POINTER - ITEM NUMBER */ + u16 FSTRDPNT; /* READ POINTER - ITEM NUMBER */ + u8 FSTFMODE[2]; /* FILE MODE - LETTER AND NUMBER */ + u16 FSTRECCT; /* NUMBER OF LOGICAL RECORDS */ + u16 FSTFCLPT; /* FIRST CHAIN LINK POINTER */ + u8 FSTRECFM; /* F*1 - RECORD FORMAT - F OR V */ +#define FSTDFIX 0xC6 /* Fixed record format (EBCDIC 'F') */ +#define FSTDVAR 0xE5 /* Variable record format (EBCDIC 'V') */ + u8 FSTFLAGS; /* F*2 - FST FLAG BYTE */ +#define FSTRWDSK 0x80 /* READ/WRITE DISK */ +#define FSTRODSK 0x00 /* READ/ONLY DISK */ +#define FSTDSFS 0x10 /* Shared File FST */ +#define FSTXRDSK 0x40 /* EXTENSION OF R/O DISK */ +#define FSTXWDSK 0xC0 /* EXTENSION OF R/W DISK */ +#define FSTEPL 0x20 /* EXTENDED PLIST */ +#define FSTDIA 0x40 /* ITEM AVAILABLE */ +#define FSTDRA 0x01 /* PREVIOUS RECORD NULL */ +#define FSTCNTRY 0x08 /* Century for date last written (0=19, 1=20),\\ + corresponds to FSTYEARW, FSTADATI. */ +#define FSTACTRD 0x04 /* ACTIVE FOR READING */ +#define FSTACTWR 0x02 /* ACTIVE FOR WRITING */ +#define FSTACTPT 0x01 /* ACTIVE FROM A POINT */ +#define FSTFILEA 0x07 /* THE FILE IS ACTIVE */ + u32 FSTLRECL; /* LOGICAL RECORD LENGTH */ + u16 FSTBLKCT; /* NUMBER OF 800 BYTE BLOCKS */ + u16 FSTYEARW; /* YEAR LAST WRITTEN */ + u32 FSTFOP; /* ALT. FILE ORIGIN POINTER */ + u32 FSTADBC; /* ALT. NUMBER OF DATA BLOCKS */ + u32 FSTAIC; /* ALT. ITEM COUNT */ + u8 FSTNLVL; /* NUMBER OF POINTER BLOCK LEVELS */ + u8 FSTPTRSZ; /* LENGTH OF A POINTER ELEMENT */ + u8 FSTADATI[6]; /* ALT. DATE/TIME(YY MM DD HH MM SS) */ + u8 FSTREALM; /* Real filemode */ + u8 FSTFLAG2; /* F*3 - FST FLAG BYTE 2 FSTFLAG2 */ +#define FSTPIPEU 0x10 /* Reserved for CMS PIPELINES usage */ + u8 reserved[2]; +}; + +#define EDF_LABEL_BLOCK_NO 3 + +#define EDF_SUPPORTED_BLOCK_SIZE 4096 + +struct fs { + struct ADT ADT; + struct list_head files; + mutex_t lock; + struct device *dev; + void *tmp_buf; +}; + +struct file { + struct FST FST; + struct list_head files; + mutex_t lock; + struct fs *fs; + char *buf; +}; + +extern struct fs *edf_mount(struct device *dev); +extern struct file *edf_lookup(struct fs *fs, char *fn, char *ft); +extern int edf_read_rec(struct file *file, char *buf, u32 recno); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/interrupt.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,103 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __INTERRUPT_H +#define __INTERRUPT_H + +/* + * I/O interruptions specific constants & structures + */ +struct io_int_code { + u32 ssid; + u32 param; +} __attribute__((packed)); + +#define PSA_INT_GPR ((u64*) 0x200) +#define PSA_TMP_PSW ((struct psw*) 0x280) + +#define IO_INT_OLD_PSW ((void*) 0x170) +#define IO_INT_NEW_PSW ((void*) 0x1f0) +#define IO_INT_CODE ((struct io_int_code*) 0xb8) + +#define EXT_INT_OLD_PSW ((void*) 0x130) +#define EXT_INT_NEW_PSW ((void*) 0x1b0) +#define EXT_INT_CODE ((u16*) 0x86) + +#define SVC_INT_OLD_PSW ((void*) 0x140) +#define SVC_INT_NEW_PSW ((void*) 0x1c0) +#define SVC_INT_CODE ((u16*) 0x8a) + +#define PGM_INT_OLD_PSW ((void*) 0x150) +#define PGM_INT_NEW_PSW ((void*) 0x1d0) +#define PGM_INT_ILC ((u8*) 0x8d) +#define PGM_INT_CODE ((u16*) 0x8e) + +/* + * Assembly stubs to call the C-handlers + */ +extern void IO_INT(void); +extern void EXT_INT(void); +extern void SVC_INT(void); +extern void PGM_INT(void); + +/** + * local_int_disable - disable interruptions & return old mask + */ +#define local_int_disable() ({ \ + unsigned long __flags; \ + __asm__ __volatile__ ( \ + "stnsm 0(%1),0xfc" : "=m" (__flags) : "a" (&__flags) ); \ + __flags; \ + }) + +/** + * local_int_restore - restore interrupt mask + * x: mask to restore + */ +#define local_int_restore(x) \ + __asm__ __volatile__("ssm 0(%0)" : : "a" (&x), "m" (x) : "memory") + +/** + * local_int_restore - restore interrupt mask + * x: mask to restore + */ +static inline int interruptable() +{ + u8 x; + + __asm__ __volatile__( + "stosm 0(%0),0x00" + : /* out */ + : /* in */ + "a" (&x), + "m" (x) + : /* clobber */ + "memory" + ); + + return (x & 0x43) != 0; +} + +extern void set_timer(void); + +/* + * The Supervisor-Service call table + */ +#define SVC_SCHEDULE 0 +#define SVC_SCHEDULE_BLOCKED 1 +#define NR_SVC 2 +extern u64 svc_table[NR_SVC]; + +/* Interrupt handlers */ +extern void __pgm_int_handler(void); +extern void __ext_int_handler(void); +extern void __io_int_handler(void); + +/* Interrupt handler stack pointer */ +extern u8 *int_stack_ptr; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/io.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,40 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __IO_H +#define __IO_H + +#include <channel.h> +#include <atomic.h> +#include <list.h> + +struct device; + +/* + * Defines an I/O operation + * + * This structure contains any and all state one should need to service any + * I/O interruption. + */ +struct io_op { + struct orb orb; /* Operation Request Block */ + + struct list_head list; /* list of in-flight operations */ + + int (*handler)(struct device *dev, struct io_op *ioop, struct irb *irb); + /* I/O specific callback */ + void (*dtor)(struct device *dev, struct io_op *ioop); + /* I/O specific destructor */ + + int err; /* return code */ + atomic_t done; /* has the operation completed */ +}; + +extern void init_io(void); +extern int submit_io(struct device *dev, struct io_op *oop, int flags); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/list.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,421 @@ +/* + * Based on list.h from Linux Kernel + */ + +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#define LIST_POISON1 ((void*) 0x8585858585858585ULL) +#define LIST_POISON2 ((void*) 0x8686868686868686ULL) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; prefetch(pos->next), pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/magic.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,16 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __MAGIC_H +#define __MAGIC_H + +#define MAGIC_PSW_IDLE_CODE 0x1D1E + +#define SLAB_MAGIC 0xe2d3c1c2 +#define SLAB_CONT_MAGIC 0xe2d3c1c3 + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/mm.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,29 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __MM_H +#define __MM_H + +extern u64 memsize; + +/* Turn Low-address protection on */ +static inline void lap_on(void) +{ + u64 cr0; + + asm volatile( + "stctg 0,0,%0\n" /* get cr0 */ + "oi %1,0x10\n" /* enable */ + "lctlg 0,0,%0\n" /* reload cr0 */ + : /* output */ + : /* input */ + "m" (cr0), + "m" (*(u64*) (((u8*)&cr0) + 4)) + ); +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/mutex.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,74 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __MUTEX_H +#define __MUTEX_H + +#include <list.h> +#include <atomic.h> +#include <spinlock.h> +#include <sched.h> +#include <interrupt.h> + +typedef struct { + atomic_t state; + spinlock_t queue_lock; + struct list_head queue; +} mutex_t; + +#define UNLOCKED_MUTEX(name) mutex_t name = { \ + .state = ATOMIC_INIT(1), \ + .queue = LIST_HEAD_INIT(name.queue), \ + .queue_lock = SPIN_LOCK_UNLOCKED, \ + } + +static inline void mutex_init(mutex_t *lock) +{ + atomic_set(&lock->state, 1); + INIT_LIST_HEAD(&lock->queue); + lock->queue_lock = SPIN_LOCK_UNLOCKED; +} + +extern void __mutex_lock(mutex_t *lock); + +static inline void mutex_lock(mutex_t *lock) +{ + /* + * if we are not interruptable, we shouldn't call any functions that + * may sleep - e.g., mutex_lock + */ + BUG_ON(!interruptable()); + + if (unlikely(atomic_add_unless(&lock->state, -1, 0) == 0)) + __mutex_lock(lock); /* the slow-path */ +} + +static inline void mutex_unlock(mutex_t *lock) +{ + struct task *task; + + spin_lock(&lock->queue_lock); + + if (likely(list_empty(&lock->queue))) { + /* no one is waiting on the queue */ + atomic_inc(&lock->state); + spin_unlock(&lock->queue_lock); + return; + } + + /* + * someone is waiting on the queue, let's dequeue them & make them + * runnable again + */ + task = list_first_entry(&lock->queue, struct task, blocked_list); + list_del(&task->blocked_list); + spin_unlock(&lock->queue_lock); + + make_runnable(task); +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/nucleus.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,83 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __NUCLEUS_H +#define __NUCLEUS_H + +#include <config.h> +#include <compiler.h> +#include <errno.h> +#include <string.h> + +extern volatile u64 ticks; + +extern struct datetime ipltime; + +/* The beginning of it all... */ +extern void start(u64 __memsize, u32 __iplsch); + +/* borrowed from Linux */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +/* borrowed from Linux */ +#define offsetof(type, member) __builtin_offsetof(type,member) + +static inline void lpswe(void *psw) +{ + asm volatile( + " lpswe 0(%0)\n" + : /* output */ + : /* input */ + "a" (psw) + : /* clobbered */ + "cc" + ); +} + +#define BUG() do { \ + asm volatile(".byte 0x00,0x00" : : : "memory"); \ + } while(0) +#define BUG_ON(cond) do { \ + if (unlikely(cond)) \ + BUG(); \ + } while(0) + +/* + * This should be as simple as a cast, but unfortunately, the BUG_ON check + * is there to make sure we never submit a truncated address to the channels + * + * In the future, the io code should check if IDA is necessary, and in that + * case allocate an IDAL & set the IDA ccw flag. Other parts of the system + * that require 31-bit address should do whatever their equivalent action + * is. + */ +static inline u32 ADDR31(void *ptr) +{ + u64 ip = (u64) ptr; + + BUG_ON(ip & ~0x7fffffffull); + + return (u32) ip; +} + +/* + * stdio.h equivalents + */ +struct console; + +extern int vprintf(struct console *con, const char *fmt, va_list args) + __attribute__ ((format (printf, 2, 0))); +extern int con_printf(struct console *con, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); + +/* + * stdarg.h equivalents + */ + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/page.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,74 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __PAGE_H +#define __PAGE_H + +#include <list.h> + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1<<PAGE_SHIFT) +#define PAGE_MASK (PAGE_SIZE-1) + +#define PAGE_INFO_BASE ((struct page*) 0x400000) + +#define ZONE_NORMAL 0 +#define ZONE_LOW 1 + +#define ZONE_NORMAL_MAX_ORDER (64-PAGE_SHIFT) +#define ZONE_LOW_MAX_ORDER (31-PAGE_SHIFT) + +/* + * This structure describes a page of memory + */ +struct page { + union { + struct list_head buddy; /* buddy allocator list */ + struct list_head guest; /* guest storage list */ + }; +}; + +/* + * Externs + */ +extern void init_pages(void); + +/* + * Static inlines + */ +static inline struct page *page_num_to_ptr(u64 pnum) +{ + struct page *base = PAGE_INFO_BASE; + + return &base[pnum]; +} + +static inline void *page_to_addr(struct page *page) +{ + u64 pagenum = (((u64) page) - ((u64) PAGE_INFO_BASE)) / sizeof(struct page); + + return (void*) (pagenum << PAGE_SHIFT); +} + +static inline struct page *addr_to_page(void *addr) +{ + struct page *base = PAGE_INFO_BASE; + + return &base[((u64) addr) >> PAGE_SHIFT]; +} + +static inline int IS_LOW_ZONE(struct page *page) +{ + return ((u64) page_to_addr(page)) < (2UL*1024*1024*1024); +} + +static inline int ZONE_TYPE(struct page *page) +{ + return IS_LOW_ZONE(page) ? ZONE_LOW : ZONE_NORMAL; +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/sched.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,210 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __SCHED_H +#define __SCHED_H + +#include <list.h> +#include <page.h> +#include <dat.h> +#include <clock.h> +#include <interrupt.h> + +#define CAN_SLEEP 1 /* safe to sleep */ +#define CAN_LOOP 2 /* safe to busy-wait */ + +#define TASK_RUNNING 0 +#define TASK_SLEEPING 1 +#define TASK_LOCKED 2 + +#define STACK_FRAME_SIZE 160 + +#define SCHED_SLICE_MS 30 /* 30ms scheduler slice */ +#define SCHED_TICKS_PER_SLICE (HZ / SCHED_SLICE_MS) + +#define HZ 100 /* number of ticks per second */ + +struct psw { + u8 _zero0:1, + r:1, /* PER Mask (R) */ + _zero1:3, + t:1, /* DAT Mode (T) */ + io:1, /* I/O Mask (IO) */ + ex:1; /* External Mask (EX) */ + + u8 key:4, /* Key */ + _zero2:1, + m:1, /* Machine-Check Mask (M) */ + w:1, /* Wait State (W) */ + p:1; /* Problem State (P) */ + + u8 as:2, /* Address-Space Control (AS) */ + cc:2, /* Condition Code (CC) */ + prog_mask:4; /* Program Mask */ + + u8 _zero3:7, + ea:1; /* Extended Addressing (EA) */ + + u32 ba:1, /* Basic Addressing (BA) */ + _zero4:31; + + u64 ptr; +}; + +/* + * saved registers for guests + * + * NOTE: some registers are saved in the SIE control block! + */ +struct guest_regs { + u64 gpr[16]; + u32 ar[16]; + u64 fpr[64]; + u32 fpcr; +}; + +/* saved registers for CP tasks */ +struct regs { + struct psw psw; + u64 gpr[16]; + u64 cr1; +}; + +/* + * These states mirror those described in chapter 4 of SA22-7832-06 + */ +enum virt_cpustate { + GUEST_STOPPED = 0, + GUEST_OPERATING, + GUEST_LOAD, + GUEST_CHECKSTOP, +}; + +#include <sie.h> + +struct virt_cpu { + /* the SIE control block is picky about alignment */ + struct sie_cb sie_cb; + + struct guest_regs regs; + u64 cpuid; + + enum virt_cpustate state; +}; + +#define TASK_NAME_LEN 16 + +/* + * This structure describes a running process. + */ +struct task { + struct regs regs; /* saved registers */ + + struct list_head run_queue; /* runnable list */ + struct list_head proc_list; /* processes list */ + struct list_head blocked_list; /* blocked on mutex/etc. list */ + + u64 slice_end_time; /* end of slice time (ticks) */ + + struct virt_cpu *cpu; /* guest cpu */ + + int state; /* state */ + + char name[TASK_NAME_LEN+1]; /* task name */ +}; + +struct virt_sys { + struct task *task; /* the virtual CPU task */ + struct user *directory; /* the directory information */ + + struct console *con; /* the login console */ + int print_ts; /* print timestamps */ + + struct list_head guest_pages; /* list of guest pages */ + struct list_head virt_devs; /* list of guest virtual devs */ + struct list_head online_users; /* list of online users */ + + struct address_space as; /* the guest storage */ +}; + +extern void init_sched(void); /* initialize the scheduler */ +extern struct task* create_task(char *name, int (*f)(void*), void*); + /* create a new task */ +extern void __schedule(struct psw *, + int newstate); /* scheduler helper - use with caution */ +extern void __schedule_svc(void); +extern void __schedule_blocked_svc(void); + +extern void make_runnable(struct task *task); + +extern void list_tasks(struct console *con, + void (*f)(struct console *, struct task*)); + +/** + * current - the current task's task struct + */ +#define current extract_task() + +#define PSA_CURRENT ((struct task**) 0x290) + +/** + * extract_task - return the current task struct + */ +static inline struct task *extract_task(void) +{ + return *PSA_CURRENT; +} + +/** + * set_task_ptr - set the stack's task struct pointer + * @task: task struct pointer to be made current + */ +static inline void set_task_ptr(struct task *task) +{ + *PSA_CURRENT = task; +} + +/** + * schedule - used to explicitly yield the cpu + */ +static inline void schedule(void) +{ + /* + * if we are not interruptable, we shouldn't call any functions that + * may sleep - schedule() is guaranteed to sleep :) + */ + BUG_ON(!interruptable()); + + asm volatile( + " svc %0\n" + : /* output */ + : /* input */ + "i" (SVC_SCHEDULE) + ); +} + +/** + * schedule_blocked - used to explicitly yield the cpu without readding the + * task to the runnable queue + */ +static inline void schedule_blocked(void) +{ + /* + * if we are not interruptable, we shouldn't call any functions that + * may sleep - schedule() is guaranteed to sleep :) + */ + BUG_ON(!interruptable()); + + asm volatile( + " svc %0\n" + : /* output */ + : /* input */ + "i" (SVC_SCHEDULE_BLOCKED) + ); +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/shell.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,49 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __SHELL_H +#define __SHELL_H + +#include <directory.h> + +#define SHELL_CMD_MAX_LEN 8 + +/* + * This file should contain only externally (from CP's point of view) + * visible interfaces. + */ +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 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)); + +/* All the different ways to reset the system */ +extern void guest_power_on_reset(struct virt_sys *sys); +extern void guest_system_reset_normal(struct virt_sys *sys); +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 run_guest(struct virt_sys *sys); +extern void handle_interception(struct virt_sys *sys); + +extern int handle_instruction(struct virt_sys *sys); +extern int handle_instruction_priv(struct virt_sys *sys); + +typedef int (*intercept_handler_t)(struct virt_sys *sys); + +#define SHELL_CMD_AUTH(s,a) do { \ + if ((s)->directory->auth > (a)) \ + return -EPERM; \ + } while(0) + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/sie.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,82 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __SIE_H +#define __SIE_H + +/* + * Taken from linux/arch/s390/include/asm/kvm_host.h + */ + +#include <atomic.h> + +/* + * Constants for sie_cb->cpuflags + */ +#define CPUSTAT_HOST 0x80000000 +#define CPUSTAT_WAIT 0x10000000 +#define CPUSTAT_ECALL_PEND 0x08000000 +#define CPUSTAT_STOP_INT 0x04000000 +#define CPUSTAT_IO_INT 0x02000000 +#define CPUSTAT_EXT_INT 0x01000000 +#define CPUSTAT_RUNNING 0x00800000 +#define CPUSTAT_RETAINED 0x00400000 +#define CPUSTAT_TIMING_SUB 0x00020000 +#define CPUSTAT_SIE_SUB 0x00010000 +#define CPUSTAT_RRF 0x00008000 +#define CPUSTAT_SLSV 0x00004000 +#define CPUSTAT_SLSR 0x00002000 +#define CPUSTAT_ZARCH 0x00000800 +#define CPUSTAT_MCDS 0x00000100 +#define CPUSTAT_SM 0x00000080 +#define CPUSTAT_G 0x00000008 +#define CPUSTAT_J 0x00000002 +#define CPUSTAT_P 0x00000001 + +struct sie_cb { + atomic_t cpuflags; /* 0x0000 */ + u32 prefix; /* 0x0004 */ + u8 reserved8[32]; /* 0x0008 */ + u64 cputm; /* 0x0028 */ + u64 ckc; /* 0x0030 */ + u64 epoch; /* 0x0038 */ + u8 reserved40[4]; /* 0x0040 */ +#define LCTL_CR0 0x8000 + u16 lctl; /* 0x0044 */ + s16 icpua; /* 0x0046 */ + u32 ictl; /* 0x0048 */ + u32 eca; /* 0x004c */ + u8 icptcode; /* 0x0050 */ + u8 reserved51; /* 0x0051 */ + u16 ihcpu; /* 0x0052 */ + u8 reserved54[2]; /* 0x0054 */ + u16 ipa; /* 0x0056 */ + u32 ipb; /* 0x0058 */ + u32 scaoh; /* 0x005c */ + u8 reserved60; /* 0x0060 */ + u8 ecb; /* 0x0061 */ + u8 reserved62[2]; /* 0x0062 */ + u32 scaol; /* 0x0064 */ + u8 reserved68[4]; /* 0x0068 */ + u32 todpr; /* 0x006c */ + u8 reserved70[16]; /* 0x0070 */ + u64 gmsor; /* 0x0080 */ + u64 gmslm; /* 0x0088 */ + struct psw gpsw; /* 0x0090 */ + u64 gg14; /* 0x00a0 */ + u64 gg15; /* 0x00a8 */ + u8 reservedb0[30]; /* 0x00b0 */ + u16 iprcc; /* 0x00ce */ + u8 reservedd0[48]; /* 0x00d0 */ + u64 gcr[16]; /* 0x0100 */ + u64 gbea; /* 0x0180 */ + u8 reserved188[120]; /* 0x0188 */ +} __attribute__((aligned(256),packed)); + +#define VCPU_ZARCH(vcpu) (atomic_read(&((vcpu)->sie_cb.cpuflags)) & CPUSTAT_ZARCH) + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/slab.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,35 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __SLAB_H +#define __SLAB_H + +#include <list.h> +#include <spinlock.h> +#include <page.h> + +struct slab { + u32 magic; /* magic */ + spinlock_t lock; /* lock to protect entire slab */ + struct list_head slab_pages; /* list of pages */ + struct slab *first; /* pointer to first slab page */ + u16 objsize; /* effective object size */ + u16 startoff; /* first object offset */ + u16 count; /* number of objects in this page */ + u16 used; /* number of used objects */ + u8 bitmap[0]; /* allocation bitmap */ +} __attribute__((packed)); + +extern int init_slab(void); + +extern struct slab *create_slab(u16 objsize, u8 align); +extern void free_slab(struct slab *slab); + +extern void *malloc(int size, int type); +extern void free(void *ptr); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/spinlock.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,99 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __SPINLOCK_H +#define __SPINLOCK_H + +/* + * Heavily based on Linux's spinlock implementation + */ + +typedef struct { + volatile unsigned int lock; +} spinlock_t; + +#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } + +static inline int __compare_and_swap(volatile unsigned int *lock, + unsigned int old, unsigned int new) +{ + asm volatile( + " cs %0,%3,%1" + : "=d" (old), "=Q" (*lock) + : "0" (old), "d" (new), "Q" (*lock) + : "cc", "memory" ); + return old; +} + +#define spin_is_locked(x) ((x)->lock != 0) + +#define SPIN_RETRY 1000 + +extern void __spin_lock_wait(spinlock_t *lp, unsigned int pc); +extern int __spin_trylock_retry(spinlock_t *lp, unsigned int pc); + +/** + * spin_lock - lock a spinlock + * @lock: lock to lock + */ +static inline void spin_lock(spinlock_t *lock) +{ + unsigned long pc = 1 | (unsigned long) __builtin_return_address(0); + + if (unlikely(__compare_and_swap(&lock->lock, 0, pc) != 0)) + __spin_lock_wait(lock, pc); +} + +/** + * spin_trylock - attempt to try to acquire a lock, but do not spin if + * acquisition would fail + * @lock: lock to lock + */ +static inline int spin_trylock(spinlock_t *lock) +{ + unsigned long pc = 1 | (unsigned long) __builtin_return_address(0); + + if (likely(__compare_and_swap(&lock->lock, 0, pc) == 0)) + return 1; + return __spin_trylock_retry(lock, pc); +} + +/** + * spin_unlock - unlock a lock + * @lock: lock to unlock + */ +static inline void spin_unlock(spinlock_t *lock) +{ + __compare_and_swap(&lock->lock, lock->lock, 0); +} + +extern void spin_lock_intsave(spinlock_t *lock, unsigned long *mask); +extern void spin_unlock_intrestore(spinlock_t *lock, unsigned long mask); + +static inline void spin_double_lock(spinlock_t *l1, spinlock_t *l2) +{ + if (l1 < l2) { + spin_lock(l1); + spin_lock(l2); + } else { + spin_lock(l2); + spin_lock(l1); + } +} + +static inline void spin_double_unlock(spinlock_t *l1, spinlock_t *l2) +{ + if (l1 < l2) { + spin_unlock(l2); + spin_unlock(l1); + } else { + spin_unlock(l1); + spin_unlock(l2); + } +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/splash.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,13 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __SPLASH_H +#define __SPLASH_H + +extern char *splash[]; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/vcpu.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,74 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __VCPU_H +#define __VCPU_H + +#include <sched.h> + +/*****************************************************************************/ +/* Guest exception queuing */ + +enum PROG_EXCEPTION { + PROG_OPERAND = 0x0001, + PROG_PRIV = 0x0002, + PROG_EXEC = 0x0003, + PROG_PROT = 0x0004, + PROG_ADDR = 0x0005, + PROG_SPEC = 0x0006, + PROG_DATA = 0x0007, +}; + +extern void queue_prog_exception(struct virt_sys *sys, enum PROG_EXCEPTION type, u64 param); + +/*****************************************************************************/ +/* Guest register reading & address calculation */ + +static inline u64 __guest_gpr(struct virt_cpu *cpu, int gpr) +{ + u64 ret = cpu->regs.gpr[gpr]; + + if (!(atomic_read(&cpu->sie_cb.cpuflags) & CPUSTAT_ZARCH)) + ret &= 0xffffffffULL; + + return ret; +} + +static inline u64 __guest_addr(struct virt_cpu *cpu, u64 disp, int x, int b) +{ + u64 mask; + + if (cpu->sie_cb.gpsw.ea && cpu->sie_cb.gpsw.ba) + mask = ~0; + else if (!cpu->sie_cb.gpsw.ea && cpu->sie_cb.gpsw.ba) + mask = 0x7fffffff; + else if (!cpu->sie_cb.gpsw.ea && !cpu->sie_cb.gpsw.ba) + mask = 0x00ffffff; + else + BUG(); + + return (disp + + (x ? __guest_gpr(cpu, x) : 0) + + (b ? __guest_gpr(cpu, b) : 0)) & mask; +} + +/*****************************************************************************/ +/* SIE Interception Param parsing & instruction decode */ + +#define IP_TO_RAW(sie) ((((u64)(sie).ipa) << 32) | ((u64)(sie).ipb)) + +static inline u64 RAW_S_1(struct virt_cpu *cpu) +{ + u64 raw = IP_TO_RAW(cpu->sie_cb); + + return __guest_addr(cpu, + (raw >> 16) & 0xfff, + (raw) >> 28 & 0xf, + 0); +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/include/vdevice.h Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,36 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#ifndef __VDEVICE_H +#define __VDEVICE_H + +#include <list.h> +#include <directory.h> +#include <sched.h> + +struct virt_device { + struct list_head devices; + enum directory_vdevtype vtype; /* VDEV_CONS, VDEV_DED, ... */ + u32 sch; /* subchannel id */ + u16 type; /* 3330, 3215, ... */ + u8 model; + + union { + struct { + struct device *rdev; + /* real device */ + } dedicate; + } u; + + struct pmcw pmcw; /* path info */ + struct scsw scsw; /* subchannel-status */ +}; + +extern int alloc_virt_dev(struct virt_sys *sys, + struct directory_vdev *dirdev, u32 sch); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/mm/Makefile Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,1 @@ +objs-mm := buddy.o page.o slab.o dat.o
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/mm/buddy.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,212 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <list.h> +#include <page.h> +#include <mm.h> +#include <buddy.h> +#include <spinlock.h> + +/* + * Lists of free page ranges + */ +static struct list_head orders_normal[64-PAGE_SHIFT]; +static struct list_head orders_low[31-PAGE_SHIFT]; + +static spinlock_t orders_lock = SPIN_LOCK_UNLOCKED; + +static void __init_buddy_alloc(u64 base, int pages, int max_order, + struct list_head *orders) +{ + int order; + struct page *p; + + for(order=0; order < max_order; order++) { + INIT_LIST_HEAD(&orders[order]); + + if (pages & (1 << order)) { + p = addr_to_page(base); + + list_add(&p->buddy, &orders[order]); + + base += (PAGE_SIZE << order); + } + } +} + +/* + * Initialize the buddy allocator. This is rather simple, and the only + * complication is that we must keep track of storage below 2GB separately + * since some IO related structures can address only the first 2GB. *sigh* + */ +void init_buddy_alloc(u64 start) +{ + u64 normal_pages; + u64 low_pages; + + if (memsize > 2UL*1024*1024*1024) { + /* There are more than 2GB of storage */ + low_pages = (2UL*1024*1024*1024 - start) >> PAGE_SHIFT; + normal_pages = (memsize - start) >> PAGE_SHIFT; + normal_pages -= low_pages; + } else { + /* All the storage is under the 2GB mark */ + low_pages = (memsize - start) >> PAGE_SHIFT; + normal_pages = 0; + } + + /* let's add all the free low storage to the lists */ + __init_buddy_alloc(start, low_pages, ZONE_LOW_MAX_ORDER, orders_low); + + /* now, let's add all the free storage above 2GB */ + __init_buddy_alloc(2UL*1024*1024*1024, normal_pages, ZONE_NORMAL_MAX_ORDER, + orders_normal); +} + +static struct page *__do_alloc_pages(int order, struct list_head *orders) +{ + struct page *page; + + if (!list_empty(&orders[order])) { + page = list_first_entry(&orders[order], struct page, buddy); + + list_del(&page->buddy); + + return page; + } + + return NULL; +} + +static struct page *__alloc_pages(int order, int type) +{ + struct page *p; + + /* Do we have to use ZONE_LOW? */ + if (type == ZONE_LOW) + goto zone_low; + + p = __do_alloc_pages(order, orders_normal); + if (p) + return p; + + /* If there was no ZONE_NORMAL page, let's try ZONE_LOW */ + +zone_low: + return __do_alloc_pages(order, orders_low); +} + +/* + * Split a given (actual) order allocation into an allocation of wanted + * order, and return the rest of pages to the unused lists + * + * E.g., + * + * pages (base): + * + * +---+---+---+---+---+---+---+---+ + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | + * +---+---+---+---+---+---+---+---+ + * + * actual = 3 + * wanted = 1 + * + * return order 2 range back to free pool: + * + * +---+---+---+---+ + * | 4 | 5 | 6 | 7 | + * +---+---+---+---+ + * + * return order 1 range back to free pool: + * + * +---+---+ + * | 2 | 3 | + * +---+---+ + * + * The End. Now, pages 2-7 are back in the free pool, and pages 0&1 are an + * order 1 allocation. + * + */ +static void __chip_pages(struct page *base, int actual, int wanted) +{ + struct page *p; + struct list_head *orders; + + orders = (IS_LOW_ZONE(base) ? orders_low : orders_normal); + + for(; actual > wanted; actual--) { + p = &base[1 << (actual-1)]; + list_add(&p->buddy, &orders[actual-1]); + } +} + +/** + * alloc_pages - allocate a series of consecutive pages + * @order: allocate 2^order consecutive pages + * @type: type of pages (<2GB, or anywhere) + */ +struct page *alloc_pages(int order, int type) +{ + struct page *page; + int gord; + unsigned long mask; + int max_order; + + spin_lock_intsave(&orders_lock, &mask); + + /* easy way */ + page = __alloc_pages(order, type); + if (page) + goto out; + + /* + * There is no page-range of the given order, let's try to find the + * smallest one larger and split it + */ + + max_order = (type == ZONE_LOW ? + ZONE_LOW_MAX_ORDER : ZONE_NORMAL_MAX_ORDER); + + for(gord=order+1; gord < max_order; gord++) { + if (gord >= max_order) + break; + + page = __alloc_pages(gord, type); + if (!page) + continue; + + __chip_pages(page, gord, order); + + goto out; + } + + /* alright, totally out of memory */ + page = NULL; + +out: + spin_unlock_intrestore(&orders_lock, mask); + + return page; +} + +void free_pages(void *ptr, int order) +{ + struct page *base = addr_to_page(ptr); + unsigned long mask; + struct list_head *orders; + + orders = IS_LOW_ZONE(base) ? orders_low : orders_normal; + + spin_lock_intsave(&orders_lock, &mask); + list_add(&base->buddy, &orders[order]); + spin_unlock_intrestore(&orders_lock, mask); + + /* + * TODO: a more complex thing we could try is to coallesce adjecent + * page ranges into one higher order one (defrag) + */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/mm/dat.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,134 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <page.h> +#include <buddy.h> +#include <dat.h> +#include <mm.h> + +static void *alloc_table(int order) +{ + struct page *p; + + p = alloc_pages(order, ZONE_NORMAL); + BUG_ON(!p); + memset(page_to_addr(p), 0xff, PAGE_SIZE << order); + + return page_to_addr(p); +} + +/** + * dat_insert_page - insert a virt->phy mapping into an address space + * @as: address space to add the mapping to + * @phy: physical address to add + * @virt: virtual address to add + */ +int dat_insert_page(struct address_space *as, u64 phy, u64 virt) +{ + struct dat_rte *region; + struct dat_ste *segment; + struct dat_pte *page; + void *ptr; + + region = as->region_table; + + if (!region) { + if (!as->segment_table) + /* + * Need to allocate the segment table + * + * max of 2048 * 8-byte entries = 16 kbytes + */ + as->segment_table = alloc_table(2); + + segment = as->segment_table; + + goto walk_segment; + } + + BUG_ON(DAT_RX(virt)); // FIXME: we don't support storage >2GB + + if (region->origin == 0xfffffffffffffUL) { + /* + * Need to allocate the segment table + * + * max of 2048 * 8-byte entries = 16 kbytes + */ + ptr = alloc_table(2); + + region->origin = ADDR_TO_RTE_ORIGIN((u64) ptr); + + region->tf = 0; /* FIXME: is this right? */ + region->i = 0; + region->tt = DAT_RTE_TT_RTT; + region->tl = 3; /* FIXME: is this right? */ + region->__reserved0 = 0; + region->__reserved1 = 0; + } + + segment = RTE_ORIGIN_TO_ADDR(region->origin); + +walk_segment: + segment += DAT_SX(virt); + + if (segment->origin == 0x1fffffffffffffUL) { + /* + * Need to allocate the page table + * + * max of 256 * 8-byte entries = 2048 bytes + */ + ptr = alloc_table(0); + + segment->origin = ADDR_TO_STE_ORIGIN((u64) ptr); + segment->p = 0; + segment->i = 0; + segment->c = 0; + segment->tt = DAT_STE_TT_ST; + segment->__reserved0 = 0; + segment->__reserved1 = 0; + segment->__reserved2 = 0; + } + + page = STE_ORIGIN_TO_ADDR(segment->origin); + page += DAT_PX(virt); + + page->pfra = phy >> PAGE_SHIFT; + page->i = 0; + page->p = 0; + page->__zero0 = 0; + page->__zero1 = 0; + page->__reserved = 0; + + return 0; +} + +void setup_dat(void) +{ + /* nothing to do! */ +} + +void load_as(struct address_space *as) +{ + struct dat_td cr1; + + BUG_ON(!as->segment_table); + + /* + * Load up the PASCE (cr1) + */ + memset(&cr1, 0, sizeof(struct dat_td)); + cr1.origin = ((u64)as->segment_table) >> 12; + cr1.dt = DAT_TD_DT_ST; + cr1.tl = 3; + + asm volatile( + " lctlg 1,1,%0\n" + : /* output */ + : /* input */ + "m" (cr1) + ); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/mm/page.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,35 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <list.h> +#include <page.h> +#include <mm.h> + +/* + * Main storage size + */ +u64 memsize; + +/* + * Initialize fields in a struct page + */ +static void __init_page(struct page *page) +{ + INIT_LIST_HEAD(&page->buddy); +} + +/* + * Initialize struct page for each available page + */ +void init_pages(void) +{ + u64 pnum; + + for(pnum=0; pnum < (memsize>>PAGE_SHIFT); pnum++) + __init_page(page_num_to_ptr(pnum)); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/mm/slab.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,286 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <magic.h> +#include <buddy.h> +#include <slab.h> +#include <page.h> + +static struct slab *generic[7]; + +/* + * Create slab caches for 16, 32, 64, 128, and 256 byte allocations + */ +int init_slab(void) +{ + generic[0] = create_slab(16, 4); + if (!generic[0]) + goto out_err; + + generic[1] = create_slab(32, 4); + if (!generic[1]) + goto out_err; + + generic[2] = create_slab(64, 4); + if (!generic[2]) + goto out_err; + + generic[3] = create_slab(128, 4); + if (!generic[3]) + goto out_err; + + generic[4] = create_slab(256, 8); + if (!generic[4]) + goto out_err; + + generic[5] = create_slab(512, 8); + if (!generic[5]) + goto out_err; + + generic[6] = create_slab(1024, 8); + if (!generic[6]) + goto out_err; + + return 0; + +out_err: + free_slab(generic[0]); + free_slab(generic[1]); + free_slab(generic[2]); + free_slab(generic[3]); + free_slab(generic[4]); + free_slab(generic[5]); + free_slab(generic[6]); + + return -ENOMEM; +} + +/** + * create_slab - Create a new slab + * @objsize: object size in bytes + * @align: object alignment in bytes (must be a power of two) + */ +struct slab *create_slab(u16 objsize, u8 align) +{ + struct page *page; + struct slab *slab; + + if (!objsize || !align) + return NULL; + + page = alloc_pages(0, ZONE_NORMAL); + if (!page) + return NULL; + + slab = page_to_addr(page); + memset(slab, 0, PAGE_SIZE); + + slab->magic = SLAB_MAGIC; + slab->lock = SPIN_LOCK_UNLOCKED; + INIT_LIST_HEAD(&slab->slab_pages); + slab->first = slab; + + align--; /* turn into a mask */ + + /* actual object size */ + if (objsize & align) + objsize += align + 1 - (objsize & align); + slab->objsize = objsize; + + /* number of objects in a page */ + slab->count = 8 * (PAGE_SIZE - sizeof(struct slab)) / (8 * objsize + 1); + + /* offset of the first object */ + slab->startoff = sizeof(struct slab) + (slab->count + 4) / 8; + if (slab->startoff & align) { + u16 tmp; + + slab->startoff += align + 1 - (slab->startoff & align); + + /* + * TODO: there's got to be a better way to ensure that we + * fit into a single page + */ + tmp = slab->startoff + slab->count * slab->objsize; + if (tmp > PAGE_SIZE) + slab->count--; + } + + slab->used = 0; + + return slab; +} + +void free_slab(struct slab *passed_slab) +{ + struct slab *slab; + + if (!passed_slab) + return; + + BUG_ON(passed_slab->magic != SLAB_MAGIC); + BUG_ON(passed_slab->used != 0); + + list_for_each_entry(slab, &passed_slab->slab_pages, slab_pages) { + BUG_ON(slab->magic != SLAB_CONT_MAGIC); + BUG_ON(slab->used != 0); + + /* + * Theoretically, we should remove the page from the list, + * but no one _really_ cares + */ + + free_pages(slab, 0); + } + + free_pages(passed_slab, 0); +} + +static inline void *__alloc_slab_obj_newpage(struct slab *slab, int type) +{ + struct page *page; + struct slab *new; + + page = alloc_pages(0, type); + if (!page) + return ERR_PTR(-ENOMEM); + + new = page_to_addr(page); + + memset(new, 0, PAGE_SIZE); + new->magic = SLAB_CONT_MAGIC; + new->first = slab; + new->objsize = slab->objsize; + new->startoff = slab->startoff; + new->count = slab->count; + + /* add it to the current slab */ + list_add_tail(&new->slab_pages, &slab->slab_pages); + + return new; +} + +static void *alloc_slab_obj(struct slab *passed_slab, int type) +{ + struct slab *slab = passed_slab; + void *obj = NULL; + int objidx; + u8 *bits; + u8 mask; + unsigned long int_mask; + + if (!slab) + return NULL; + + BUG_ON(passed_slab->magic != SLAB_MAGIC); + + spin_lock_intsave(&passed_slab->lock, &int_mask); + + /* + * Does the first slab page have an unused object _AND_ is in the + * right zone? + */ + if (slab->used < slab->count && ZONE_TYPE(addr_to_page(slab)) == type) + goto alloc; + + /* + * No. Find the first slab page that has unused objects + */ + list_for_each_entry(slab, &passed_slab->slab_pages, slab_pages) + if (slab->used < slab->count && + ZONE_TYPE(addr_to_page(slab)) == type) + goto alloc; + + /* + * None of the pages have an unused object. Let's allocate another + * page + */ + + slab = __alloc_slab_obj_newpage(passed_slab, type); + if (IS_ERR(slab)) + /* + * FIXME: if we tried to get a ZONE_NORMAL and failed, + * shouldn't we retry with ZONE_LOW? + */ + goto out; + + +alloc: + /* found a page */ + for (objidx = 0; objidx < slab->count; objidx++) { + bits = slab->bitmap + (objidx/8); + + mask = 1 << (7 - (objidx % 8)); + + if (*bits & mask) + continue; + + slab->used++; + *bits |= mask; + + obj = ((u8*) slab) + slab->startoff + slab->objsize * objidx; + break; + } + +out: + spin_unlock_intrestore(&passed_slab->lock, int_mask); + + return obj; +} + +static void free_slab_obj(void *ptr) +{ + struct slab *slab; + int objidx; + u8 *bits; + unsigned long int_mask; + + /* get the slab object ptr */ + slab = (struct slab *) (((u64) ptr) & ~0xfff); + + spin_lock_intsave(&slab->first->lock, &int_mask); + + /* calculate the object number */ + objidx = (((u64) ptr) - ((u64) slab) - slab->startoff) / slab->objsize; + + /* update the bitmap */ + bits = slab->bitmap + (objidx/8); + *bits &= ~(1 << (7 - (objidx % 8))); + + if (--slab->used) { + /* FIXME: free the page? */ + } + + spin_unlock_intrestore(&slab->first->lock, int_mask); +} + +void *malloc(int size, int type) +{ + if (!size) + return NULL; + if (size <= 16) + return alloc_slab_obj(generic[0], type); + if (size <= 32) + return alloc_slab_obj(generic[1], type); + if (size <= 64) + return alloc_slab_obj(generic[2], type); + if (size <= 128) + return alloc_slab_obj(generic[3], type); + if (size <= 256) + return alloc_slab_obj(generic[4], type); + if (size <= 512) + return alloc_slab_obj(generic[5], type); + if (size <= 1024) + return alloc_slab_obj(generic[6], type); + return NULL; +} + +void free(void *ptr) +{ + if (ptr) + free_slab_obj(ptr); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/nucleus/Makefile Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,2 @@ +objs-nucleus := init.o io.o printf.o ebcdic.o int.o ext.o svc.o pgm.o \ + spinlock.o mutex.o sched.o
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/nucleus/ebcdic.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,161 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <ebcdic.h> + +/* + * Tables taken from Linux's arch/s390/kernel/ebcdic.c + */ + +/* + * ASCII (IBM PC 437) -> EBCDIC 037 + */ +u8 ascii2ebcdic_table[256] = +{ + /*00 NUL SOH STX ETX EOT ENQ ACK BEL */ + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, + /*08 BS HT LF VT FF CR SO SI */ + /* ->NL */ + 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, + /*18 CAN EM SUB ESC FS GS RS US */ + /* ->IGS ->IRS ->IUS */ + 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F, + /*20 SP ! " # $ % & ' */ + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, + /*28 ( ) * + , - . / */ + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + /*30 0 1 2 3 4 5 6 7 */ + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + /*38 8 9 : ; < = > ? */ + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + /*40 @ A B C D E F G */ + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + /*48 H I J K L M N O */ + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + /*50 P Q R S T U V W */ + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + /*58 X Y Z [ \ ] ^ _ */ + 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D, + /*60 ` a b c d e f g */ + 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + /*68 h i j k l m n o */ + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + /*70 p q r s t u v w */ + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + /*78 x y z { | } ~ DL */ + 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, + /*80*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*88*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*90*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*98*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*A0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*A8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*B0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*B8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*C0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*C8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*D0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*D8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*E0 sz */ + 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*E8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*F0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*F8*/ + 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF +}; + +/* + * EBCDIC 037 -> ASCII (IBM PC 437) + */ +u8 ebcdic2ascii_table[256] = +{ + /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */ + 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, + /* 0x08 -GE -SPS -RPT VT FF CR SO SI */ + 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC + -ENP ->LF */ + 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, + /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB + -IUS */ + 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC + -INP */ + 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, + /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL + -SW */ + 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, + /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */ + 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, + /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */ + 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, + /* 0x40 SP RSP ä ---- */ + 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, + /* 0x48 . < ( + | */ + 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, + /* 0x50 & ---- */ + 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, + /* 0x58 ß ! $ * ) ; */ + 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA, + /* 0x60 - / ---- Ä ---- ---- ---- */ + 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, + /* 0x68 ---- , % _ > ? */ + 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + /* 0x70 ---- ---- ---- ---- ---- ---- ---- */ + 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + /* 0x78 * ` : # @ ' = " */ + 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + /* 0x80 * a b c d e f g */ + 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + /* 0x88 h i ---- ---- ---- */ + 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, + /* 0x90 ° j k l m n o p */ + 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + /* 0x98 q r ---- ---- */ + 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, + /* 0xA0 ~ s t u v w x */ + 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + /* 0xA8 y z ---- ---- ---- ---- */ + 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, + /* 0xB0 ^ ---- § ---- */ + 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, + /* 0xB8 ---- [ ] ---- ---- ---- ---- */ + 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07, + /* 0xC0 { A B C D E F G */ + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + /* 0xC8 H I ---- ö ---- */ + 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, + /* 0xD0 } J K L M N O P */ + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + /* 0xD8 Q R ---- ü */ + 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, + /* 0xE0 \ S T U V W X */ + 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + /* 0xE8 Y Z ---- Ö ---- ---- ---- */ + 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, + /* 0xF0 0 1 2 3 4 5 6 7 */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + /* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */ + 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07 +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/nucleus/ext.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,51 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <interrupt.h> +#include <sched.h> + +/* + * This is the tick counter, it starts at 0 when we initialize the nucleus + */ +volatile u64 ticks; + +void set_timer(void) +{ + u64 time = 1000 * 1000 * CLK_MICROSEC / HZ; + + asm volatile( + "spt %0\n" /* set timer value */ + : /* output */ + : /* input */ + "m" (time) + ); +} + +void __ext_int_handler(void) +{ + if (*EXT_INT_CODE == 0x1005) { + /* + * This is the timer, let's call the scheduler. + */ + + ticks++; + + set_timer(); + + /* + * No need to save the registers, the assembly stub that + * called this function already saved them at PSA_INT_GPR + */ + if (!(ticks % SCHED_TICKS_PER_SLICE)) { + __schedule(EXT_INT_OLD_PSW, TASK_SLEEPING); + + /* unreachable */ + BUG(); + } + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/nucleus/init.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,207 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <mm.h> +#include <dat.h> +#include <slab.h> +#include <page.h> +#include <buddy.h> +#include <io.h> +#include <sched.h> +#include <device.h> +#include <console.h> +#include <interrupt.h> +#include <magic.h> +#include <shell.h> + +static struct psw new_io_psw = { + .ea = 1, + .ba = 1, + + .ptr = (u64) &IO_INT, +}; + +static struct psw new_ext_psw = { + .ea = 1, + .ba = 1, + + .ptr = (u64) &EXT_INT, +}; + +static struct psw new_svc_psw = { + .ea = 1, + .ba = 1, + + .ptr = (u64) &SVC_INT, +}; + +static struct psw new_pgm_psw = { + .ea = 1, + .ba = 1, + + .ptr = (u64) &PGM_INT, +}; + +u8 *int_stack_ptr; + +/* the time HVF got IPLd */ +struct datetime ipltime; + +static void init_int_stack(void) +{ + struct page *page; + + page = alloc_pages(0, ZONE_NORMAL); + BUG_ON(!page); + + int_stack_ptr = PAGE_SIZE + (u8*)page_to_addr(page); +} + +static void idle_task_body(void) +{ + /* + * Warning: hack alert! The following overrides what __init_task + * set, this allows us to skip the usual start_task wrapper. + */ + current->regs.psw.w = 1; + current->regs.psw.ptr = MAGIC_PSW_IDLE_CODE; + + /* + * Load the new PSW that'll wait with special magic code set + */ + lpswe(¤t->regs.psw); + + BUG(); +} + +/* + * This is where everything starts + */ +void start(u64 __memsize, u32 __iplsch) +{ + u64 first_free_page; + u64 struct_page_bytes; + struct psw psw; + struct console *opcon; /* operator's console */ + + /* + * ticks starts at 0 + */ + ticks = 0; + + /* + * save total system memory size + */ + memsize = __memsize; + + /* + * Initialize struct page entries + */ + init_pages(); + + /* + * Calculate address of the first free page (we may have to round + * up) + */ + struct_page_bytes = (memsize >> PAGE_SHIFT) * sizeof(struct page); + + first_free_page = (u64) PAGE_INFO_BASE + struct_page_bytes; + if (struct_page_bytes & (PAGE_SIZE-1)) + first_free_page += PAGE_SIZE - (struct_page_bytes & (PAGE_SIZE-1)); + + /* + * Initialize the buddy allocator + */ + init_buddy_alloc(first_free_page); + + /* + * Initialize slab allocator default caches + */ + init_slab(); + + /* + * Set up interrupt PSWs + */ + memcpy(IO_INT_NEW_PSW, &new_io_psw, sizeof(struct psw)); + memcpy(EXT_INT_NEW_PSW, &new_ext_psw, sizeof(struct psw)); + memcpy(SVC_INT_NEW_PSW, &new_svc_psw, sizeof(struct psw)); + memcpy(PGM_INT_NEW_PSW, &new_pgm_psw, sizeof(struct psw)); + + /* Turn on Low-address Protection */ + lap_on(); + + /* + * Set up page table entries for the nucleus + */ + setup_dat(); + + /* + * Allocate & initialize the interrupt stack + */ + init_int_stack(); + + /* + * Initialize the io subsystem + */ + init_io(); + + /* + * Register all the device drivers + */ + register_drivers(); + + /* + * Time to enable interrupts => load new psw + */ + memset(&psw, 0, sizeof(struct psw)); + psw.io = 1; + psw.ea = 1; + psw.ba = 1; + + asm volatile( + " larl %%r1,0f\n" + " stg %%r1,%0\n" + " lpswe %1\n" + "0:\n" + : /* output */ + "=m" (psw.ptr) + : /* input */ + "m" (psw) + : /* clobbered */ + "r1" + ); + + /* + * Let's discover all the devices attached + */ + scan_devices(); + + /* + * Initialize the process scheduler + */ + init_sched(); + + /* + * IPL is more or less done + */ + get_parsed_tod(&ipltime); + + opcon = start_oper_console(); + + 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); + + /* + * THIS IS WHERE THE IDLE TASK BEGINS + */ + + idle_task_body(); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/nucleus/int.S Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,121 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +.text + +#include <interrupt.h> + +# +# IO Interrupt +# + .align 4 +.globl IO_INT + .type IO_INT, @function +IO_INT: + # save regs + STMG %r0,%r15,0x200(%r0) + + # set up stack + LARL %r15, int_stack_ptr + LG %r15, 0(%r15) + AGHI %r15,-160 + + LARL %r14, __io_int_handler + BALR %r14, %r14 # call the real handler + + # restore regs + LMG %r0,%r15,0x200(%r0) + + LPSWE 0x170 # go back to what we interrupted + + +# +# External Interrupt +# + .align 4 +.globl EXT_INT + .type EXT_INT, @function +EXT_INT: + # save regs + STMG %r0,%r15,0x200(%r0) + + # set up stack + LARL %r15, int_stack_ptr + LG %r15, 0(%r15) + AGHI %r15,-160 + + LARL %r14, __ext_int_handler + BALR %r14, %r14 # call the real handler + + # + # NOTE: we may never return from the C-interrupt handler if the + # interrupt was caused by the timer clock, in which case the + # scheduler kicks in, and gives control to someone else + # + + # restore regs + LMG %r0,%r15,0x200(%r0) + + LPSWE 0x130 # go back to what we interrupted + + +# +# Supervisor-Call Interrupt +# + .align 4 +.globl SVC_INT + .type SVC_INT, @function +SVC_INT: + # save regs + STMG %r0,%r15,0x200(%r0) + + # set up stack + LARL %r15, int_stack_ptr + LG %r15, 0(%r15) + AGHI %r15,-160 + + # find the right handler + LARL %r14, svc_table # table address + LGH %r2, 0x8a # interruption code + SLL %r2, 3 + # byte offset into table + LG %r14, 0(%r2,%r14) # load value from table + + BALR %r14, %r14 # call the real handler + + # restore regs + LMG %r0,%r15,0x200(%r0) + + LPSWE 0x140 # go back to what we interrupted + + +# +# Program Interrupt +# + .align 4 +.globl PGM_INT + .type PGM_INT, @function +PGM_INT: + # save regs + STMG %r0,%r15,0x200(%r0) + + # set up stack + LARL %r15, int_stack_ptr + LG %r15, 0(%r15) + AGHI %r15,-160 + + LARL %r14, __pgm_int_handler + BALR %r14, %r14 # call the real handler + + # + # NOTE: we may never return from the C-interrupt handler + # + + # restore regs + LMG %r0,%r15,0x200(%r0) + + LPSWE 0x150 # go back to what we interrupted
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/nucleus/io.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,213 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <channel.h> +#include <io.h> +#include <interrupt.h> +#include <device.h> +#include <sched.h> +#include <atomic.h> +#include <spinlock.h> +#include <buddy.h> +#include <sched.h> + +/* + * Helper function to make sure the io_op has everything set right + */ +static int __verify_io_op(struct io_op *ioop) +{ + // FIXME: check everything that makes sense to check + return 0; +} + +static void __reset_reserved_fields(struct io_op *ioop) +{ + ioop->orb.__zero1 = 0; + ioop->orb.__zero2 = 0; + + ioop->orb.__reserved1 = 0; + ioop->orb.__reserved2 = 0; + ioop->orb.__reserved3 = 0; + ioop->orb.__reserved4 = 0; + ioop->orb.__reserved5 = 0; + ioop->orb.__reserved6 = 0; +} + +/* NOTE: assumes dev->q_lock is held */ +static void __submit_io(struct device *dev) +{ + struct io_op *ioop; + int err; + + if (dev->q_cur) + return; + + if (list_empty(&dev->q_out)) + return; + + ioop = list_entry(dev->q_out.next, struct io_op, list); + + err = start_sch(dev->sch, &ioop->orb); + if (!err) { + list_del(&ioop->list); + dev->q_cur = ioop; + } else + ioop->err = err; +} + +/* + * Submit an I/O request to a subchannel, and set up everything needed to + * handle the operation + */ +int submit_io(struct device *dev, struct io_op *ioop, int flags) +{ + static atomic_t op_id_counter; + unsigned long intmask; + int err = -EBUSY; + + err = __verify_io_op(ioop); + if (err) + return 0; + + /* make sure all reserved fields have the right values */ + __reset_reserved_fields(ioop); + + ioop->err = 0; + ioop->orb.param = atomic_inc_return(&op_id_counter); + atomic_set(&ioop->done, 0); + + /* add it to the list of ops */ + spin_lock_intsave(&dev->q_lock, &intmask); + list_add_tail(&ioop->list, &dev->q_out); + + __submit_io(dev); /* try to submit an IO right now */ + spin_unlock_intrestore(&dev->q_lock, intmask); + + if (flags & CAN_LOOP) { + while(!atomic_read(&ioop->done)) + ; + } else if (flags & CAN_SLEEP) { + while(!atomic_read(&ioop->done)) + schedule(); + } + + return 0; +} + +/* + * Initialize the channel I/O subsystem + */ +void init_io(void) +{ + u64 cr6; + + /* enable all I/O interrupt classes */ + asm volatile( + "stctg 6,6,%0\n" /* get cr6 */ + "oi %1,0xff\n" /* enable all */ + "lctlg 6,6,%0\n" /* reload cr6 */ + : /* output */ + : /* input */ + "m" (cr6), + "m" (*(u64*) (((u8*)&cr6) + 4)) + ); +} + +static int default_io_handler(struct device *dev, struct io_op *ioop, struct irb *irb) +{ + ioop->err = -EAGAIN; + + /* Unit check? */ + if (irb->scsw.dev_status & 0x02) + ioop->err = -EUCHECK; /* FIXME: we should bail */ + + /* Device End is set, we're done */ + if (irb->scsw.dev_status & 0x04) + ioop->err = 0; + + return 0; +} + +static void __cpu_initiated_io(struct device *dev, struct io_op *ioop, struct irb *irb) +{ + unsigned long intmask; + + ioop->err = test_sch(dev->sch, irb); + + if (!ioop->err && ioop->handler) + ioop->handler(dev, ioop, irb); + else if (!ioop->err) + default_io_handler(dev, ioop, irb); + + /* + * We can do this, because the test_sch function sets ->err, and + * therefore regardless of ->handler being defined, ->err will have + * a reasonable value + */ + if (ioop->err == -EAGAIN) + return; /* leave handler registered */ + + /* ...and remove it form the list */ + spin_lock_intsave(&dev->q_lock, &intmask); + dev->q_cur = NULL; + + __submit_io(dev); /* try to submit another IO */ + spin_unlock_intrestore(&dev->q_lock, intmask); + + /* flag io_op as done... */ + atomic_set(&ioop->done, 1); + + /* call the destructor if there is one */ + if (ioop->dtor) + ioop->dtor(dev, ioop); +} + +static void __dev_initiated_io(struct device *dev, struct irb *irb) +{ +} + +/* + * I/O Interrupt handler (C portion) + */ +void __io_int_handler(void) +{ + unsigned long intmask; + struct io_op *ioop; + struct device *dev; + struct irb irb; + + dev = find_device_by_sch(IO_INT_CODE->ssid); + BUG_ON(IS_ERR(dev)); + + spin_lock_intsave(&dev->q_lock, &intmask); + ioop = dev->q_cur; + spin_unlock_intrestore(&dev->q_lock, intmask); + + if (ioop && ioop->orb.param == IO_INT_CODE->param && + dev->sch == IO_INT_CODE->ssid) { + /* + * CPU-initiated operation + */ + + __cpu_initiated_io(dev, ioop, &irb); + dev_put(dev); + return; + } + + /* + * device-initiated operation + */ + BUG_ON(test_sch(dev->sch, &irb)); + + atomic_inc(&dev->attention); + + if (dev->dev->interrupt) + dev->dev->interrupt(dev, &irb); + else + __dev_initiated_io(dev, &irb); + dev_put(dev); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/nucleus/mutex.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,25 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <mutex.h> + +/* slow-path mutex locking */ +void __mutex_lock(mutex_t *lock) +{ + spin_lock(&lock->queue_lock); + + if (unlikely(atomic_add_unless(&lock->state, -1, 0))) { + spin_unlock(&lock->queue_lock); + return; /* aha! someone released it & it's ours now! */ + } + + list_add_tail(¤t->blocked_list, &lock->queue); + + spin_unlock(&lock->queue_lock); + + schedule_blocked(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/nucleus/pgm.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,69 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <interrupt.h> +#include <ebcdic.h> +#include <vsprintf.h> + +static char abend_msg_buf[1024]; + +/* + * All is lost! All hands abandon ship! + * + * Try to write out a message to a special buffer to help debugging, and + * then stop the CPU. + */ +static void abend(void) +{ + int ret; + + ret = snprintf(abend_msg_buf, 1024, + "ABEND %04x" + "PSW ILC %d" + "%016llx%016llx" + "GPR " + "%016llx%016llx%016llx%016llx" + "%016llx%016llx%016llx%016llx" + "%016llx%016llx%016llx%016llx" + "%016llx%016llx%016llx%016llx", + *PGM_INT_CODE, (*PGM_INT_ILC) >> 1, + *((u64*) PGM_INT_OLD_PSW), *(((u64*) PGM_INT_OLD_PSW)+1), + PSA_INT_GPR[0], PSA_INT_GPR[1], PSA_INT_GPR[2], PSA_INT_GPR[3], + PSA_INT_GPR[4], PSA_INT_GPR[5], PSA_INT_GPR[6], PSA_INT_GPR[7], + PSA_INT_GPR[8], PSA_INT_GPR[9], PSA_INT_GPR[10], PSA_INT_GPR[11], + PSA_INT_GPR[12], PSA_INT_GPR[13], PSA_INT_GPR[14], PSA_INT_GPR[15] + ); + + if (ret) + ascii2ebcdic((u8 *) abend_msg_buf, ret); + + /* + * halt the cpu + * + * NOTE: we don't care about not clobbering registers as when this + * code executes, the CPU will be stopped. + */ + asm volatile( + "LR %%r15, %0 # buffer pointer\n" + "SR %%r1, %%r1 # not used, but should be zero\n" + "SR %%r3, %%r3 # CPU Address\n" + "SIGP %%r1, %%r3, 0x05 # Signal, order 0x05\n" + : /* out */ + : /* in */ + "a" (abend_msg_buf) + ); + + /* + * If SIGP failed, loop forever + */ + for(;;); +} + +void __pgm_int_handler(void) +{ + abend(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/nucleus/printf.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,51 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <channel.h> +#include <console.h> +#include <directory.h> +#include <ebcdic.h> +#include <slab.h> +#include <clock.h> +#include <sched.h> +#include <vsprintf.h> +#include <stdarg.h> + +int vprintf(struct console *con, const char *fmt, va_list args) +{ + struct datetime dt; + char buf[128]; + int off = 0; + int ret; + + if (!con->sys || (con->sys && con->sys->print_ts)) { + memset(&dt, 0, sizeof(dt)); + ret = get_parsed_tod(&dt); + off = snprintf(buf, 128, "%02d:%02d:%02d ", dt.th, dt.tm, + dt.ts); + } + + ret = vsnprintf(buf+off, 128-off, fmt, args); + if (ret) { + ascii2ebcdic((u8 *) buf, off+ret); + con_write(con, (u8 *) buf, off+ret); + } + + return ret; +} + +int con_printf(struct console *con, const char *fmt, ...) +{ + va_list args; + int r; + + va_start(args, fmt); + r = vprintf(con, fmt, args); + va_end(args); + + return r; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/nucleus/sched.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,299 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <sched.h> +#include <page.h> +#include <buddy.h> +#include <slab.h> +#include <magic.h> + +/* list of all runnable processes */ +static struct list_head runnable; + +/* list of all processes in the system */ +static struct list_head processes; + +/* idle task */ +static struct task idle_task; + +/** + * start_task - helper used to start the task's code + * @f: function to execute + */ +static void start_task(int (*f)(void*), void *data) +{ + /* + * Start executing the code + */ + if (f) + (*f)(data); + + /* + * Done, now, it's time to cleanup + * + * FIXME: + * - delete from processes list + * - free stack page + * - free struct + * - schedule + */ + BUG(); +} + +/** + * __init_task - helper to initialize the task structure + * @task: task struct to initialize + * @f: pointer to function to execute + * @stack: pointer to the page for stack + */ +static void __init_task(struct task *task, void *f, void *data, void *stack) +{ + memset(task, 0, sizeof(struct task)); + + task->regs.psw.io = 1; + task->regs.psw.ex = 1; + task->regs.psw.ea = 1; + task->regs.psw.ba = 1; + + /* code to execute */ + task->regs.psw.ptr = (u64) start_task; + + task->regs.gpr[2] = (u64) f; + task->regs.gpr[3] = (u64) data; + task->regs.gpr[15] = ((u64) stack) + PAGE_SIZE - STACK_FRAME_SIZE; + + task->state = TASK_SLEEPING; +} + +/** + * init_idle_task - initialize the idle task + * + * Since the initial thread of execution already has a stack, and the task + * struct is a global variable, all that is left for us to do is to + * associate the current stack with idle_task. + */ +static void init_idle_task(void) +{ + u64 stack; + + stack = ((u64) &stack) & ~(PAGE_SIZE-1); + + __init_task(&idle_task, NULL, NULL, (void*) stack); + set_task_ptr(&idle_task); + + /* + * NOTE: The idle task is _not_ supposed to be on either of the + * two process lists. + */ +} + +/** + * create_task - create a new task + * @name: name for the task + * @f: function pointer to where thread of execution should begin + * @data: arbitrary data to pass to the task + */ +struct task* create_task(char *name, int (*f)(void *), void *data) +{ + struct page *page; + struct task *task; + + /* + * Allocate a page for stack, and struct task itself + */ + page = alloc_pages(0, ZONE_NORMAL); + task = malloc(sizeof(struct task), ZONE_NORMAL); + if (!page || !task) + goto out; + + /* + * Set up task's state + */ + __init_task(task, f, data, page_to_addr(page)); + + strncpy(task->name, name, TASK_NAME_LEN); + + /* + * Add the task to the scheduler lists + */ + list_add_tail(&task->proc_list, &processes); + list_add_tail(&task->run_queue, &runnable); + + return task; + +out: + free(task); + free_pages(page_to_addr(page), 0); + + return ERR_PTR(-ENOMEM); +} + +/** + * __sched - core of the scheduler code. This decides which task to run + * next, and switches over to it + */ +static void __sched(int force_idle) +{ + struct task *next; + + /* + * If there are no runnable tasks, let's use the idle thread + */ + if (force_idle || list_empty(&runnable)) { + next = &idle_task; + goto run; + } + + next = list_first_entry(&runnable, struct task, run_queue); + BUG_ON(!next); + + /* + * Remove the new task from the run queue & mark it as running + */ + list_del(&next->run_queue); + next->state = TASK_RUNNING; + +run: + next->slice_end_time = (force_idle) ? force_idle : ticks + SCHED_TICKS_PER_SLICE; + + /* + * NOTE: Because we need to load the registers _BEFORE_ we issue + * lpswe, we have to place the new psw into PSA and use register 0 + */ + memcpy(PSA_TMP_PSW, &next->regs.psw, sizeof(struct psw)); + set_task_ptr(next); + + load_pasce(next->regs.cr1); + + /* + * Load the next task + * + * FIXME: fp? ar? cr? + */ + asm volatile( + "lmg %%r0,%%r15,%0\n" /* load gpr */ + "lpswe %1\n" /* load new psw */ + : /* output */ + : /* input */ + "m" (next->regs.gpr[0]), + "m" (*PSA_TMP_PSW) + ); + + /* unreachable */ + BUG(); +} + +/** + * schedule_preempted - called to switch tasks + */ +void __schedule(struct psw *old_psw, int newstate) +{ + struct task *prev; + int force_idle = 0; + + /* + * Save last process's state + */ + + prev = current; + BUG_ON(!prev); + + /* + * Save the registers (gpr, psw, ...) + * + * FIXME: fp? ar? cr? + */ + memcpy(prev->regs.gpr, PSA_INT_GPR, sizeof(u64)*16); + memcpy(&prev->regs.psw, old_psw, sizeof(struct psw)); + + /* + * Idle task doesn't get added back to the queue + */ + if (prev == &idle_task) + goto go; + + store_pasce(&prev->regs.cr1); + + /* + * Add back on the queue + */ + prev->state = newstate; + if (newstate != TASK_LOCKED) + list_add_tail(&prev->run_queue, &runnable); + + /* + * If the previous task didn't use it's full slice, force idle_task + * to take over. + */ + if (prev->slice_end_time >= (ticks + SCHED_TICKS_PER_SLICE)) + force_idle = prev->slice_end_time; + +go: + /* + * Run the rest of the scheduler that selects the next task and + * context switches + */ + __sched(force_idle); +} + +/** + * __schedule_svc - wrapper for the supervisor-service call handler + */ +void __schedule_svc(void) +{ + __schedule(SVC_INT_OLD_PSW, TASK_SLEEPING); +} + +/** + * __schedule_blocked__svc - wrapper for the supervisor-service call handler + */ +void __schedule_blocked_svc(void) +{ + __schedule(SVC_INT_OLD_PSW, TASK_LOCKED); +} + +/* + * Initialize the schduler, and all associated structures + */ +void init_sched(void) +{ + u64 cr0; + + INIT_LIST_HEAD(&runnable); + INIT_LIST_HEAD(&processes); + + init_idle_task(); + + /* enable cpu timer interrupt subclass */ + asm volatile( + "stctg 0,0,%0\n" /* get cr0 */ + "oi %1,0x04\n" /* enable cpu timer subclass */ + "ni %1,0x7f\n" /* disable clock comp */ + "lctlg 0,0,%0\n" /* reload cr0 */ + : /* output */ + : /* input */ + "m" (cr0), + "m" (*(((u8*)&cr0) + 6)) + ); + + set_timer(); +} + +void list_tasks(struct console *con, + void (*f)(struct console *, struct task*)) +{ + struct task *t; + + list_for_each_entry(t, &processes, proc_list) + f(con, t); +} + +void make_runnable(struct task *task) +{ + task->state = TASK_SLEEPING; + list_add_tail(&task->run_queue, &runnable); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/nucleus/spinlock.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,50 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <interrupt.h> +#include <spinlock.h> + +void __spin_lock_wait(spinlock_t *lp, unsigned int pc) +{ + while (1) { + if (__compare_and_swap(&lp->lock, 0, pc) == 0) + return; + } +} + +int __spin_trylock_retry(spinlock_t *lp, unsigned int pc) +{ + int count = SPIN_RETRY; + + while (count-- > 0) + if (__compare_and_swap(&lp->lock, 0, pc) == 0) + return 1; + return 0; +} + +/** + * spin_lock_intsave - disable interrupts and lock + * @lock: lock to lock + * @mask: pointer to where interrupt mask will be stored + */ +void spin_lock_intsave(spinlock_t *lock, unsigned long *mask) +{ + *mask = local_int_disable(); + spin_lock(lock); +} + +/** + * spin_unlock_intrestore - unlock and restore interrupt flags flags + * @lock: lock to unlock + * @mask: mask to restore + */ +void spin_unlock_intrestore(spinlock_t *lock, unsigned long mask) +{ + spin_unlock(lock); + local_int_restore(mask); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/nucleus/svc.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,15 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <sched.h> +#include <interrupt.h> + +u64 svc_table[NR_SVC] = { + (u64) __schedule_svc, + (u64) __schedule_blocked_svc, +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/scripts/Makefile.build Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,41 @@ +# +# (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> +# +# This file is released under the GPLv2. See the COPYING file for more +# details. +# + +# +# Build a single directory (built-in.o) +# + +.PHONY: all + +.PRECIOUS: %.o + +include scripts/Makefile.commands + +override DIR := $(patsubst %/,%,$(DIR)) +include $(DIR)/Makefile + +OBJS := $(foreach obj,$(objs-$(DIR)),$(patsubst %,$(DIR)/%,$(obj))) + +all: $(DIR)/built-in.o + @echo -n + +%/built-in.o: $(OBJS) + $(call o-to-builtin,$(OBJS),$@) + +%.o: %.S + $(call s-to-o,$<,$@) + +%.s: %.c + $(call c-to-s,$<,$@) + +%.o: %.c + $(call c-to-o,$<,$@) + +shell/directory.c: shell/directory_structs.c + +shell/directory_structs.c: hvf.directory + $(call gendir,$<,$@)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/scripts/Makefile.commands Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,64 @@ +cmd-ar=$(AR) rc $(1) $(2) +# +# (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> +# +# This file is released under the GPLv2. See the COPYING file for more +# details. +# +cmd-c-to-o=$(CC) $(CFLAGS) $(NUCLEUSCFLAGS) -c -o $(2) $(1) +cmd-c-to-s=$(CC) $(CFLAGS) $(NUCLEUSCFLAGS) -S -o $(2) $(1) +cmd-s-to-o=$(AS) -m64 -o $(2) $(1) +cmd-o-to-builtin=$(LD) $(LDFLAGS) -r -o $(2) $(1) +cmd-link-hvf=$(LD) $(LDFLAGS) -T scripts/linker.script -o $(2) $(1) +cmd-link-ipl=$(LD) -melf64_s390 -T linker.script -o $(2) $(1) +cmd-objcopy-t=$(OBJCOPY) -O binary -j .text $(1) $(2) +cmd-objcopy-tdr=$(OBJCOPY) -O binary -j .text -j .data -j .rodata -j .rodata.str1.2 $(1) $(2) +cmd-genipl-rdr=bash scripts/gen_rdr_ccws.sh $(1) +cmd-genipl-tape=bash scripts/gen_tape_ipl_s.sh $(1) $(2) +cmd-concat=cat $(1) > $(2) +cmd-pad=bash scripts/pad.sh $(1) $(2) +cmd-clean=rm -f $(1) +cmd-rclean=rm -rf $(1) +cmd-cscope=cscope -R -b +cmd-gendir=bash scripts/gen-dir.sh $(1) $(2) + +ifeq ($V,1) +ar=$(cmd-ar) +c-to-o=$(cmd-c-to-o) +c-to-s=$(cmd-c-to-s) +c-to-o-ipl=$(cmd-c-to-o-ipl) +s-to-o=$(cmd-s-to-o) +o-to-builtin=$(cmd-o-to-builtin) +link-hvf=$(cmd-link-hvf) +link-ipl=$(cmd-link-ipl) +objcopy-t=$(cmd-objcopy-t) +objcopy-tdr=$(cmd-objcopy-tdr) +genipl-rdr=$(cmd-genipl-rdr) +genipl-tape=$(cmd-genipl-tape) +concat=$(cmd-concat) +pad=$(cmd-pad) +clean=$(cmd-clean) +rclean=$(cmd-rclean) +cscope=$(cmd-cscope) +gendir=$(cmd-gendir) +else +ar=@echo " [AR] $(1)"; $(cmd-ar) +c-to-o=@echo " [CC] $(2)"; $(cmd-c-to-o) +c-to-s=@echo " [CC] $(2)"; $(cmd-c-to-s) +c-to-o-ipl=@echo " [CC] $(2)"; $(cmd-c-to-o-ipl) +s-to-o=@echo " [AS] $(2)"; $(cmd-s-to-o) +o-to-builtin=@echo " [LD] $(2)"; $(cmd-o-to-builtin) +link-hvf=@echo " [LD] hvf"; $(cmd-link-hvf) +link-ipl=@echo " [LD] $2"; $(cmd-link-ipl) +objcopy-t=@echo " [OBJCOPY] $2"; $(cmd-objcopy-t) +objcopy-tdr=@echo " [OBJCOPY] $2"; $(cmd-objcopy-tdr) +genipl-rdr=@echo " [GENRDR] $1"; $(cmd-genipl-rdr) +genipl-tape=@echo " [GENTAPE] $2"; $(cmd-genipl-tape) +concat=@echo " [CONCAT] $2"; $(cmd-concat) +pad=@echo " [PAD] $1 (multiple of $2 bytes)"; $(cmd-pad) +clean=@echo " [CLEAN] $1"; $(cmd-clean) +rclean=@echo " [CLEAN] $1"; $(cmd-rclean) +cscope=@echo " [CSCOPE] cscope.out"; $(cmd-cscope) +gendir=@echo " [DIRECT] $1 -> $2"; $(cmd-gendir) +endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/scripts/extract-version.sh Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,12 @@ +#!/bin/sh + +v=`git describe 2> /dev/null` + +case "$v" in + "") + awk '/^VERSION=/ { print substr($0,9); exit; }' < Makefile + ;; + *) + echo "$v" + ;; +esac
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/scripts/gen-dir.sh Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,99 @@ +#!/bin/sh + +if [ $# -ne 2 ]; then + echo "Usage: $0 <directory> <outfile>" >&2 + exit 1 +fi + +userid="" + +close_devlist() +{ +cat >> directory.devlist <<DONE + { /* END */ .type = VDEV_INVAL, }, +}; +DONE +echo " }," >> directory.userlist +} + +parse_line() +{ + case "$1" in + USER) + [ ! -z "$userid" ] && close_devlist + + echo "static struct directory_vdev __directory_$2[] = {" >> directory.devlist + echo " {" >> directory.userlist + echo " .userid = \"$2\"," >> directory.userlist + echo " .auth = '$3'," >> directory.userlist + echo " .devices = __directory_$2," >> directory.userlist + + userid="$2" + ;; + MACHINE) + ;; + STORAGE) + tmp=`echo $2 | sed -e 's/[KMG]//g'` + case "$2" in + *K) size="${tmp}ULL * 1024ULL" ;; + *M) size="${tmp}ULL * 1024ULL * 1024ULL" ;; + *G) size="${tmp}ULL * 1024ULL * 1024ULL * 1024ULL" ;; + *) size="$2ULL" ;; + esac + echo " .storage_size = $size," >> directory.userlist + ;; + CONSOLE) + echo " { /* CON */ .type = VDEV_CONS, .vdev = 0x$2, }," >> directory.devlist + ;; + SPOOL) + case "$4" in + READER) + echo " { /* RDR */ .type = VDEV_SPOOL, .vdev = 0x$2, .u.spool = { .type = 0x$3, .model = 1 }, }," >> directory.devlist + ;; + PUNCH) + echo " { /* PUN */ .type = VDEV_SPOOL, .vdev = 0x$2, .u.spool = { .type = 0x$3, .model = 1 }, }," >> directory.devlist + ;; + PRINT) + echo " { /* PRT */ .type = VDEV_SPOOL, .vdev = 0x$2, .u.spool = { .type = 0x$3, .model = 1 }, }," >> directory.devlist + ;; + esac + ;; + MDISK) + echo " { /* MDISK */ .type = VDEV_MDISK, .vdev = 0x$2, .u.mdisk = { .rdev = 0x$6, .cyloff = $4, .cylcnt = $5, }, }," >> directory.devlist + ;; + DEDICATE) + echo " { /* DED */ .type = VDEV_DED, .vdev = 0x$2, .u.dedicate = { .rdev = 0x$3, }, }," >> directory.devlist + ;; + *) + echo "Error near:" "$@" >&2 + exit 2 + ;; + esac +} + +open_userlist() +{ + echo "static struct user directory[] = {" > directory.userlist +} + +close_userlist() +{ +cat >> directory.userlist <<DONE + { /* END */ .userid = NULL, }, +}; +DONE +} + +rm -f directory.devlist +open_userlist +cat "$1" | while read line ; do + [ -z "$line" ] && continue + + parse_line $line +done +close_devlist +close_userlist + +cat directory.devlist directory.userlist > $2 + +rm -f directory.devlist directory.userlist
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/scripts/gen-docs.sh Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,101 @@ +write_docs() +{ +cat "$1" | awk -v fmt="$2" ' +BEGIN{ + docdir = "doc/commands"; + + if (fmt == "txt") { + cmd_title_open = ""; + cmd_title_close = ""; + sec_hdr_open = ""; + sec_hdr_close = ""; + par_open = ""; + par_close = ""; + pre_open = ""; + pre_close = ""; + } else if (fmt == "html") { + cmd_title_open = "<h1>"; + cmd_title_close = "</h1>"; + sec_hdr_open = "<h2>"; + sec_hdr_close = "</h2>"; + par_open = "<p>"; + par_close = "</p>"; + pre_open = "<pre>"; + pre_close = "</pre>"; + } else { + printf "ERROR: unknown format \"%s\"\n", fmt; + exit; + } + + fname = ""; +} + +/^[/ ]\*!!! / { + # begin a new command + if (fname != "") + close(fname); + + name=""; + fname=""; + for(i=2; i<=NF; i+=1) { + name = name $i " "; + fname = fname $i "_"; + } + name = substr(name, 1, length(name)-1); + fname = docdir "/" fmt "/" substr(fname, 1, length(fname)-1) "." fmt; + + print "Writing out ", fname; + + print cmd_title_open > fname; + print name >> fname; + print cmd_title_close >> fname; +} + +/^[/ ]\*!! AUTH / { + # output an authorization block + print sec_hdr_open >> fname; + print "Authorization" >> fname; + print sec_hdr_close par_open >> fname; + print $3 >> fname; + printf par_close >> fname; +} + +/^[/ ]\*!! PURPOSE$/ { + # output purpose section header + print sec_hdr_open >> fname; + print "Purpose" >> fname; + print sec_hdr_close >> fname; +} + +/^[/ ]\*!! NOTES$/ { + # output notes section header + print sec_hdr_open >> fname; + print "Usage Notes" >> fname; + print sec_hdr_close >> fname; +} + +/^[/ ]\*!p / { + # preformated verbatim line + print pre_open substr($0, 6) pre_close >> fname; +} + +/^[/ ]\*! / { + # verbatim line + print substr($0, 5) >> fname; +} + +/^[/ ]\*!$/ { + # just make a new paragraph + print substr($0, 5) >> fname; +} +' +} + +mkdir -p doc/commands/txt +mkdir -p doc/commands/html + +for srcf in shell/cmd_*.c ; do + echo "Inspecting $srcf..." + write_docs $srcf txt + write_docs $srcf html +done
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/scripts/linker.script Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,8 @@ +SECTIONS +{ + ENTRY(start) + . = 0x100000; + .text : { *(.text) } + .data : { *(.data) } + .bss : { *(.bss) } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/scripts/pad.sh Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,11 @@ +#!/bin/bash + +# pad <fname> <multiple> + +len=`stat -c %s "$1"` +dif=`expr $len % "$2"` + +if [ $dif -ne 0 ]; then + dif=`expr "$2" - $dif` + dd if=/dev/zero bs=1 count=$dif 2> /dev/null >> "$1" +fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/Makefile Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,2 @@ +objs-shell := init.o directory.o cmds.o disassm.o guest.o reset.o intercept.o \ + guest_ipl.o exception.o instruction.o instruction_priv.o splash.o
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/cmd_beginstop.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,36 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +/* + *!!! BEGIN + *!! SYNTAX + *! \tok{\sc BEgin} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Starts/resumes virtual machine execution. + */ +static int cmd_begin(struct virt_sys *sys, char *cmd, int len) +{ + sys->task->cpu->state = GUEST_OPERATING; + return 0; +} + +/* + *!!! STOP + *!! SYNTAX + *! \tok{\sc STOP} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Stops virtual machine execution. + */ +static int cmd_stop(struct virt_sys *sys, char *cmd, int len) +{ + sys->task->cpu->state = GUEST_STOPPED; + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/cmd_display.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,558 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +static char* parse_addrspec(u64 *val, u64 *len, char *s) +{ + u64 tmp; + int parsed = 0; + + tmp = 0; + while(!(*s == '\0' || + *s == ' ' || + *s == '\t')) { + if (*s >= '0' && *s <= '9') + tmp = 16*tmp + (*s - '0'); + else if ((*s >= 'A' && *s <= 'F') || + (*s >= 'a' && *s <= 'f')) + tmp = 16*tmp + 10 + ((*s & ~0x20) - 'A'); + else if (*s == '.' && parsed) + break; + else + return ERR_PTR(-EINVAL); + + s++; + parsed = 1; + } + + if (len) { + *len = 0; + if (*s == '.') { + s = __extract_hex(s+1, len); + if (IS_ERR(s)) + parsed = 0; + } + } + + *val = tmp; + + return (parsed == 1 ? s : ERR_PTR(-EINVAL)); +} + +enum display_fmt { + FMT_NUMERIC = 0, + FMT_INSTRUCT, +}; + +static void __display_storage_instruct(struct virt_sys *sys, u64 guest_addr, + u64 mlen) +{ + int ret; + char buf[64]; + int ilen; + u64 val; + u64 host_addr; + + u64 end_addr; + + /* walk the page tables to find the real page frame */ + ret = virt2phy_current(guest_addr, &host_addr); + if (ret) { + con_printf(sys->con, "DISPLAY: Specified address is not part of " + "guest configuration (RC=%d,%d)\n", -EFAULT, ret); + return; + } + + if (!mlen) + mlen = 1; + + end_addr = guest_addr + mlen; + + while(guest_addr < end_addr) { + /* + * FIXME: make sure crossing page-boundary doesn't break + * give us garbage + */ + ilen = disassm((unsigned char*) host_addr, buf, 64); + + if ((host_addr & PAGE_MASK) >= (PAGE_SIZE-ilen)) { + con_printf(sys->con, "DISPLAY: Instruction spans page " + "boundary - not supported\n"); + break; + } + + /* load the dword at the address, and shift it to the LSB part */ + val = *((u64*)host_addr) >> 8*(sizeof(u64) - ilen); + + con_printf(sys->con, "R%016llX %0*llX%*s %s\n", guest_addr, + 2*ilen, val, /* inst hex dump */ + 12-2*ilen, "", /* spacer */ + buf); + + host_addr += ilen; + guest_addr += ilen; + } +} + +static void __display_storage_numeric(struct virt_sys *sys, u64 guest_addr, + u64 mlen) +{ + char buf[80]; + char *bp; + + u64 host_addr; + int this_len; + + int ret; + + /* round down */ + guest_addr &= ~((u64) 0x3); + + /* walk the page tables to find the real page frame */ + ret = virt2phy_current(guest_addr, &host_addr); + if (ret) + goto fault; + + if (mlen > 4) + mlen = (mlen >> 2) + !!(mlen & 0x3); + else + mlen = 1; + + while(mlen && !ret) { + this_len = (mlen > 4) ? 4 : mlen; + + mlen -= this_len; + + bp = buf; + bp += snprintf(bp, 80, "R%016llX ", guest_addr); + + while(this_len) { + bp += snprintf(bp, 80 - (bp - buf), "%08X ", + *(u32*)host_addr); + + guest_addr += 4; + host_addr += 4; + this_len--; + + /* loop if we're not crossing a page, or if we're done */ + if (((guest_addr & PAGE_MASK) != 0) || !mlen) + continue; + + /* + * We will attempt to walk further along guest + * storage, and are about to cross a page boundary, + * walk the page tables to find the real page frame + */ + ret = virt2phy_current(guest_addr, &host_addr); + if (ret) + break; + } + + con_printf(sys->con, "%s\n", buf); + } + +fault: + if (ret) + con_printf(sys->con, "DISPLAY: The address %016llX is not part of " + "guest configuration (RC=%d,%d)\n", guest_addr, -EFAULT, ret); +} + +/* + *!!! DISPLAY STORAGE + *!! SYNTAX + *! \tok{\sc Display} \tok{\sc STOrage} + *! \begin{stack} \\ \deftok{N} \\ \tok{I} \end{stack} + *! <addr> + *! \begin{stack} \\ \tok{.} <length> \end{stack} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Displays a portion of guest's storage. + *!! OPERANDS + *! \cbstart + *! \item[addr] is the guest storage address. + *! \item[length] is the number of bytes to display. If not specified, 4 is + *! assumed. + *! \cbend + *!! SDNAREPO + *!! OPTIONS + *! \cbstart + *! \item[N] display guest storage in numeric format. + *! \item[I] display guest storage in instruction format. + *! \cbend + *!! SNOITPO + *!! NOTES + *! \cbstart + *! \item Currently, the instruction display does not support page-boundary + *! crossing. + *! \cbend + *!! SETON + *!! EXAMPLES + *! D STO 200\\ + *! D STO N200.10\\ + *! D STO I1234.200 + */ +static int cmd_display_storage(struct virt_sys *sys, char *cmd, int len) +{ + u64 guest_addr; + u64 mlen = 0; + enum display_fmt fmt; + + switch (cmd[0]) { + case 'N': case 'n': + /* numeric */ + cmd++; + fmt = FMT_NUMERIC; + break; + case 'I': case 'i': + /* instruction */ + cmd++; + fmt = FMT_INSTRUCT; + break; + default: + /* numeric */ + fmt = FMT_NUMERIC; + break; + } + + cmd = parse_addrspec(&guest_addr, &mlen, cmd); + if (IS_ERR(cmd)) { + con_printf(sys->con, "DISPLAY: Invalid addr-spec\n"); + return 0; + } + + if (fmt == FMT_INSTRUCT) + __display_storage_instruct(sys, guest_addr, mlen); + else + __display_storage_numeric(sys, guest_addr, mlen); + + return 0; +} + +/* + *!!! DISPLAY SIECB + *!! SYNTAX + *! \tok{\sc Display} \tok{\sc SIECB} + *!! XATNYS + *!! AUTH E + *!! PURPOSE + *! Displays hexdump of the guest's SIE control block. + */ +static int cmd_display_siecb(struct virt_sys *sys, char *cmd, int len) +{ + u32 *val; + int i; + + SHELL_CMD_AUTH(sys, 'E'); + + val = (u32*) &sys->task->cpu->sie_cb; + + con_printf(sys->con, "SIECB FOR %s AT %p\n", + sys->directory->userid, val); + for(i=0; i<(sizeof(struct sie_cb)/sizeof(u32)); i+=4) + con_printf(sys->con, "%03lX %08X %08X %08X %08X\n", + i*sizeof(u32), val[i], val[i+1], val[i+2], + val[i+3]); + + return 0; +} + +/* + *!!! DISPLAY GPR + *!! SYNTAX + *! \tok{\sc Display} \tok{\sc Gpr} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Displays the guest's general purpose registers + */ +static int cmd_display_gpr(struct virt_sys *sys, char *cmd, int len) +{ + con_printf(sys->con, "GR 0 = %016llX %016llX\n", + sys->task->cpu->regs.gpr[0], + sys->task->cpu->regs.gpr[1]); + con_printf(sys->con, "GR 2 = %016llX %016llX\n", + sys->task->cpu->regs.gpr[2], + sys->task->cpu->regs.gpr[3]); + con_printf(sys->con, "GR 4 = %016llX %016llX\n", + sys->task->cpu->regs.gpr[4], + sys->task->cpu->regs.gpr[5]); + con_printf(sys->con, "GR 6 = %016llX %016llX\n", + sys->task->cpu->regs.gpr[6], + sys->task->cpu->regs.gpr[7]); + con_printf(sys->con, "GR 8 = %016llX %016llX\n", + sys->task->cpu->regs.gpr[8], + sys->task->cpu->regs.gpr[9]); + con_printf(sys->con, "GR 10 = %016llX %016llX\n", + sys->task->cpu->regs.gpr[10], + sys->task->cpu->regs.gpr[11]); + con_printf(sys->con, "GR 12 = %016llX %016llX\n", + sys->task->cpu->regs.gpr[12], + sys->task->cpu->regs.gpr[13]); + con_printf(sys->con, "GR 14 = %016llX %016llX\n", + sys->task->cpu->regs.gpr[14], + sys->task->cpu->regs.gpr[15]); + return 0; +} + +/* + *!!! DISPLAY FPCR + *!! SYNTAX + *! \tok{\sc Display} \tok{\sc FPCR} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Displays the guest's floating point control register + */ +static int cmd_display_fpcr(struct virt_sys *sys, char *cmd, int len) +{ + con_printf(sys->con, "FPCR = %08X\n", sys->task->cpu->regs.fpcr); + return 0; +} + +/* + *!!! DISPLAY FPR + *!! SYNTAX + *! \tok{\sc Display} \tok{\sc Fpr} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Displays the guest's floating point registers + */ +static int cmd_display_fpr(struct virt_sys *sys, char *cmd, int len) +{ + con_printf(sys->con, "FR 0 = %016llX %016llX\n", + sys->task->cpu->regs.fpr[0], + sys->task->cpu->regs.fpr[1]); + con_printf(sys->con, "FR 2 = %016llX %016llX\n", + sys->task->cpu->regs.fpr[2], + sys->task->cpu->regs.fpr[3]); + con_printf(sys->con, "FR 4 = %016llX %016llX\n", + sys->task->cpu->regs.fpr[4], + sys->task->cpu->regs.fpr[5]); + con_printf(sys->con, "FR 6 = %016llX %016llX\n", + sys->task->cpu->regs.fpr[6], + sys->task->cpu->regs.fpr[7]); + con_printf(sys->con, "FR 8 = %016llX %016llX\n", + sys->task->cpu->regs.fpr[8], + sys->task->cpu->regs.fpr[9]); + con_printf(sys->con, "FR 10 = %016llX %016llX\n", + sys->task->cpu->regs.fpr[10], + sys->task->cpu->regs.fpr[11]); + con_printf(sys->con, "FR 12 = %016llX %016llX\n", + sys->task->cpu->regs.fpr[12], + sys->task->cpu->regs.fpr[13]); + con_printf(sys->con, "FR 14 = %016llX %016llX\n", + sys->task->cpu->regs.fpr[14], + sys->task->cpu->regs.fpr[15]); + return 0; +} + +/* + *!!! DISPLAY CR + *!! SYNTAX + *! \tok{\sc Display} \tok{\sc Cr} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Displays the guest's control registers + */ +static int cmd_display_cr(struct virt_sys *sys, char *cmd, int len) +{ + con_printf(sys->con, "CR 0 = %016llX %016llX\n", + sys->task->cpu->sie_cb.gcr[0], + sys->task->cpu->sie_cb.gcr[1]); + con_printf(sys->con, "CR 2 = %016llX %016llX\n", + sys->task->cpu->sie_cb.gcr[2], + sys->task->cpu->sie_cb.gcr[3]); + con_printf(sys->con, "CR 4 = %016llX %016llX\n", + sys->task->cpu->sie_cb.gcr[4], + sys->task->cpu->sie_cb.gcr[5]); + con_printf(sys->con, "CR 6 = %016llX %016llX\n", + sys->task->cpu->sie_cb.gcr[6], + sys->task->cpu->sie_cb.gcr[7]); + con_printf(sys->con, "CR 8 = %016llX %016llX\n", + sys->task->cpu->sie_cb.gcr[8], + sys->task->cpu->sie_cb.gcr[9]); + con_printf(sys->con, "CR 10 = %016llX %016llX\n", + sys->task->cpu->sie_cb.gcr[10], + sys->task->cpu->sie_cb.gcr[11]); + con_printf(sys->con, "CR 12 = %016llX %016llX\n", + sys->task->cpu->sie_cb.gcr[12], + sys->task->cpu->sie_cb.gcr[13]); + con_printf(sys->con, "CR 14 = %016llX %016llX\n", + sys->task->cpu->sie_cb.gcr[14], + sys->task->cpu->sie_cb.gcr[15]); + return 0; +} + +/* + *!!! DISPLAY AR + *!! SYNTAX + *! \tok{\sc Display} \tok{\sc Ar} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Displays the guest's access registers + */ +static int cmd_display_ar(struct virt_sys *sys, char *cmd, int len) +{ + con_printf(sys->con, "AR 0 = %08X %08X\n", + sys->task->cpu->regs.ar[0], + sys->task->cpu->regs.ar[1]); + con_printf(sys->con, "AR 2 = %08X %08X\n", + sys->task->cpu->regs.ar[2], + sys->task->cpu->regs.ar[3]); + con_printf(sys->con, "AR 4 = %08X %08X\n", + sys->task->cpu->regs.ar[4], + sys->task->cpu->regs.ar[5]); + con_printf(sys->con, "AR 6 = %08X %08X\n", + sys->task->cpu->regs.ar[6], + sys->task->cpu->regs.ar[7]); + con_printf(sys->con, "AR 8 = %08X %08X\n", + sys->task->cpu->regs.ar[8], + sys->task->cpu->regs.ar[9]); + con_printf(sys->con, "AR 10 = %08X %08X\n", + sys->task->cpu->regs.ar[10], + sys->task->cpu->regs.ar[11]); + con_printf(sys->con, "AR 12 = %08X %08X\n", + sys->task->cpu->regs.ar[12], + sys->task->cpu->regs.ar[13]); + con_printf(sys->con, "AR 14 = %08X %08X\n", + sys->task->cpu->regs.ar[14], + sys->task->cpu->regs.ar[15]); + return 0; +} + +/* + *!!! DISPLAY PSW + *!! SYNTAX + *! \tok{\sc Display} \tok{\sc PSW} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Displays the guest's PSW. + *! + *! \cbstart + *! If the guest is in ESA/390 mode, the 8-byte PSW is displayed. + *! + *! If the guest is in z/Architecture mode, the 16-byte PSW is displayed. + *! \cbend + */ +static int cmd_display_psw(struct virt_sys *sys, char *cmd, int len) +{ + u32 *ptr = (u32*) &sys->task->cpu->sie_cb.gpsw; + + if (VCPU_ZARCH(sys->task->cpu)) + con_printf(sys->con, "PSW = %08X %08X %08X %08X\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + else + con_printf(sys->con, "PSW = %08X %08X\n", + ptr[0], ptr[1]); + + return 0; +} + +static void __do_display_schib(struct console *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", + vdev->sch, vdev->pmcw.dev_num, vdev->pmcw.interrupt_param, + vdev->pmcw.isc, ((vdev->pmcw.e << 7) | + (vdev->pmcw.lm << 5) | + (vdev->pmcw.mm << 3) | + (vdev->pmcw.d << 2) | + (vdev->pmcw.t << 1) | + (vdev->pmcw.v)), + vdev->pmcw.lpm, vdev->pmcw.pnom, vdev->pmcw.lpum, + vdev->pmcw.pim, + /* MBI */ + vdev->pmcw.pom, vdev->pmcw.pam, + vdev->pmcw.chpid[0], vdev->pmcw.chpid[1], + vdev->pmcw.chpid[2], vdev->pmcw.chpid[3], + vdev->pmcw.chpid[4], vdev->pmcw.chpid[5], + vdev->pmcw.chpid[6], vdev->pmcw.chpid[7]); +} + +/* + *!!! DISPLAY SCHIB + *!! SYNTAX + *! \tok{\sc Display} \tok{\sc SCHIB} + *! \begin{stack} \tok{ALL} \\ <schib> \end{stack} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Displays the guest's subchannel control block information + */ +static int cmd_display_schib(struct virt_sys *sys, char *cmd, int len) +{ + struct virt_device *vdev; + u64 sch; + int all; + + if (strcasecmp(cmd, "ALL")) { + cmd = __extract_hex(cmd, &sch); + if (IS_ERR(cmd)) + return PTR_ERR(cmd); + + /* sch number must be: X'0001____' */ + if ((sch & 0xffff0000) != 0x00010000) + return -EINVAL; + + all = 0; + } else + all = 1; + + /* find the virtual device */ + + list_for_each_entry(vdev, &sys->virt_devs, devices) { + if ((vdev->sch == (u32) sch) || all) { + if (!all || all == 1) { + con_printf(sys->con, "SCHIB DEV INT-PARM ISC FLG LP " + "PNO LPU PI MBI PO PA CHPID0-3 CHPID4-7\n"); + all = (all ? 2 : 0); + } + + __do_display_schib(sys->con, vdev); + + if (!all) + break; + } + } + + return 0; +} + +static struct cpcmd cmd_tbl_display[] = { + {"AR", cmd_display_ar, NULL}, + {"A", cmd_display_ar, NULL}, + + {"CR", cmd_display_cr, NULL}, + {"C", cmd_display_cr, NULL}, + + {"FPCR", cmd_display_fpcr, NULL}, + + {"FPR", cmd_display_fpr, NULL}, + {"FP", cmd_display_fpr, NULL}, + {"F", cmd_display_fpr, NULL}, + + {"GPR", cmd_display_gpr, NULL}, + {"GP", cmd_display_gpr, NULL}, + {"G", cmd_display_gpr, NULL}, + + {"PSW", cmd_display_psw, NULL}, + + {"SCHIB", cmd_display_schib, NULL}, + + {"SIECB", cmd_display_siecb, NULL}, + + {"STORAGE", cmd_display_storage, NULL}, + {"STORAG", cmd_display_storage, NULL}, + {"STORA", cmd_display_storage, NULL}, + {"STOR", cmd_display_storage, NULL}, + {"STO", cmd_display_storage, NULL}, + {"", NULL, NULL}, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/cmd_enable.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,62 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +/* + *!!! ENABLE + *!! SYNTAX + *! \tok{\sc ENAble} + *! \begin{stack} \tok{ALL} \\ <rdev> \end{stack} + *!! XATNYS + *!! AUTH A + *!! PURPOSE + *! Enables a real device. + */ +static int cmd_enable(struct virt_sys *sys, char *cmd, int len) +{ + u64 devnum; + struct device *dev; + struct console *con; + + if (!strcasecmp(cmd, "ALL")) { + con_printf(sys->con, "ENABLE ALL not yet implemented!\n"); + return 0; + } + + cmd = __extract_hex(cmd, &devnum); + if (IS_ERR(cmd)) + return PTR_ERR(cmd); + + /* device number must be 16-bit */ + if (devnum & ~0xffffUL) + return -EINVAL; + + dev = find_device_by_ccuu(devnum); + if (IS_ERR(dev)) { + con_printf(sys->con, "Device %04llX not found in configuration\n", devnum); + return 0; + } + + if (atomic_read(&dev->in_use)) { + con_printf(sys->con, "Device %04llX is already in use\n", devnum); + dev_put(dev); + return 0; + } + + if (!dev->dev->enable) { + con_printf(sys->con, "Device type %-4s cannot be enabled\n", + type2name(dev->type)); + return 0; + } + + con = dev->dev->enable(dev); + if (IS_ERR(con)) { + con_printf(sys->con, "Failed to enable %04llX\n", devnum); + return PTR_ERR(con); + } + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/cmd_helpers.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,84 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +static char* __extract_dec(char *str, u64 *val) +{ + u64 res; + u64 tmp; + int len; + + if (!str || !val) + return ERR_PTR(-EINVAL); + + res = 0; + len = -1; + + for (; str && *str != '\0'; str++, len++) { + if (*str >= '0' && *str <= '9') + tmp = *str - '0'; + else if (*str == ' ' || *str == '\t') + break; + else + return ERR_PTR(-EINVAL); + + res = (res * 10) + tmp; + } + + if (len == -1) + return ERR_PTR(-EINVAL); + + *val = res; + + return str; +} + +static char* __extract_hex(char *str, u64 *val) +{ + u64 res; + u64 tmp; + int len; + + if (!str || !val) + return ERR_PTR(-EINVAL); + + res = 0; + len = -1; + + for (; str && *str != '\0'; str++, len++) { + if (*str >= '0' && *str <= '9') + tmp = *str - '0'; + else if (*str >= 'A' && *str <= 'F') + tmp = *str - 'A' + 10; + else if (*str >= 'a' && *str <= 'f') + tmp = *str - 'a' + 10; + else if (*str == ' ' || *str == '\t') + break; + else + return ERR_PTR(-EINVAL); + + res = (res << 4) | tmp; + } + + if (len == -1) + return ERR_PTR(-EINVAL); + + *val = res; + + return str; +} + +static char* __consume_ws(char *str) +{ + if (!str) + return str; + + /* consume any extra whitespace */ + while(*str == ' ' || *str == '\t') + str++; + + return str; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/cmd_logon.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +/* + *!!! LOGON + *!! SYNTAX + *! \tok{\sc LOGON} <userid> + *!! XATNYS + *!! AUTH G + *!! 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) +{ + con_printf(sys->con, "ALREADY LOGGED ON\n"); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/cmd_query.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,350 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +static char *__guest_state_to_str(enum virt_cpustate st) +{ + switch (st) { + case GUEST_STOPPED: return "STOPPED"; + case GUEST_OPERATING: return "RUNNING"; + case GUEST_LOAD: return "LOADING"; + case GUEST_CHECKSTOP: return "CHECK-STOP"; + } + + return "???"; +} + +static void display_rdev(struct console *con, struct device *dev) +{ + char buf[40]; + + buf[0] = '\0'; + + 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->sch); +} + +static void display_vdev(struct console *con, struct virt_device *vdev) +{ + switch (vdev->vtype) { + case VDEV_CONS: + con_printf(con, "CONS %04X 3215 ON %s %04X %s SCH = %05X\n", + vdev->pmcw.dev_num, + type2name(con->dev->type), // FIXME? + con->dev->ccuu, + con->sys->print_ts ? "TS" : "NOTS", + vdev->sch); + break; + case VDEV_DED: + con_printf(con, "%-4s %04X %04X ON DEV %04X SCH = %05X\n", + type2name(vdev->type), + vdev->pmcw.dev_num, + vdev->type, + vdev->u.dedicate.rdev->ccuu, + vdev->sch); + break; + case VDEV_SPOOL: + con_printf(con, "%-4s %04X %04X SCH = %05X\n", + type2name(vdev->type), + vdev->pmcw.dev_num, vdev->type, + vdev->sch); + break; + case VDEV_MDISK: + con_printf(con, "DASD %04X 3390 %6d CYL ON DASD %04X SCH = %05X\n", + vdev->pmcw.dev_num, + 0, /* FIXME: cyl count */ + 0, /* FIXME: rdev */ + vdev->sch); + break; + case VDEV_LINK: + con_printf(con, "LINK %04X TO %s %04X SCH = %05X\n", + vdev->pmcw.dev_num, + "????", /* FIXME: userid */ + 0xffff, /* FIXME: user's vdev # */ + vdev->sch); + break; + default: + con_printf(con, "???? unknown device type (%04X, %05X)\n", + vdev->pmcw.dev_num, vdev->sch); + break; + } +} + +static void display_task(struct console *con, struct task *task) +{ + char state; + + switch(task->state) { + case TASK_RUNNING: state = 'R'; break; + case TASK_SLEEPING: state = 'S'; break; + case TASK_LOCKED: state = 'L'; break; + default: state = '?'; break; + } + + con_printf(con, "%*s %p %c %016llX\n", -TASK_NAME_LEN, task->name, + task, state, task->regs.psw.ptr); +} + +/* + *!!! QUERY TIME + *!! SYNTAX + *! \tok{\sc Query} \tok{\sc TIME} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Displays the current time + */ +static int cmd_query_cplevel(struct virt_sys *sys, char *cmd, int len) +{ + con_printf(sys->con, "HVF version " VERSION "\n"); + con_printf(sys->con, "IPL at %02d:%02d:%02d UTC %04d-%02d-%02d\n", + ipltime.th, ipltime.tm, ipltime.ts, ipltime.dy, + ipltime.dm, ipltime.dd); + + return 0; +} + +/* + *!!! QUERY CPLEVEL + *!! SYNTAX + *! \tok{\sc Query} \tok{\sc CPLEVEL} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Displays the HVF version and time of IPL + */ +static int cmd_query_time(struct virt_sys *sys, char *cmd, int len) +{ + struct datetime dt; + + get_parsed_tod(&dt); + + con_printf(sys->con, "TIME IS %02d:%02d:%02d UTC %04d-%02d-%02d\n", + dt.th, dt.tm, dt.ts, dt.dy, dt.dm, dt.dd); + + return 0; +} + +/* + *!!! QUERY ARCHMODE + *!! SYNTAX + *! \tok{\sc Query} \tok{\sc ARCHMODE} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Displays the virtual machine's current architecture mode. + */ +static int cmd_query_archmode(struct virt_sys *sys, char *cmd, int len) +{ + char *mode = (VCPU_ZARCH(sys->task->cpu)) ? "z/Arch" : "ESA390"; + + con_printf(sys->con, "ARCHMODE = %s\n", mode); + + return 0; +} + +/* + *!!! QUERY VIRTUAL + *!! SYNTAX + *! \tok{\sc Query} \tok{\sc Virtual} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Lists all of the guest's virtual devices + */ +static int cmd_query_virtual(struct virt_sys *sys, char *cmd, int len) +{ + struct virt_device *vdev; + + con_printf(sys->con, "CPU 00 ID %016llX %s\n", + sys->task->cpu->cpuid, + __guest_state_to_str(sys->task->cpu->state)); + con_printf(sys->con, "STORAGE = %lluM\n", sys->directory->storage_size >> 20); + + list_for_each_entry(vdev, &sys->virt_devs, devices) + display_vdev(sys->con, vdev); + + return 0; +} + +static void __cmd_query_real_cpus(struct virt_sys *sys) +{ + con_printf(sys->con, "CPU %02d ID %016llX RUNNING\n", + getcpuaddr(), + getcpuid()); +} + +static void __cmd_query_real_stor(struct virt_sys *sys) +{ + con_printf(sys->con, "STORAGE = %lluM\n", memsize >> 20); +} + +enum { + QUERY_CPUS = 1 << 0, + QUERY_STOR = 1 << 1, + QUERY_DEVS = 1 << 2, + QUERY_DEVNUM = 1 << 3, +}; + +/* + *!!! QUERY REAL + *!! SYNTAX + *! \tok{\sc Query} \tok{\sc Real} + *! \begin{stack} + *! \\ + *! \tok{\sc\bf ALL} \\ + *! \tok{\sc CPUS} \\ + *! \tok{\sc STORage} \\ + *! <rdev> + *! \end{stack} + *!! XATNYS + *!! AUTH A + *!! PURPOSE + *! \cbstart + *! Lists the host's real devices, CPUs, and storage + *! \cbend + *!! NOTES + *! \cbstart + *! \item Specifying real device numbers is not supported at the moment. + *! Instead, use QUERY REAL ALL to display all devices attached to the + *! system. + *! \cbend + *!! SETON + */ +static int cmd_query_real(struct virt_sys *sys, char *cmd, int len) +{ + int what = 0; + u64 devnum; + + SHELL_CMD_AUTH(sys, 'A'); + + if (strnlen(cmd, len) == 0) { + what = QUERY_CPUS | QUERY_STOR | QUERY_DEVS; + } else if (!strcasecmp(cmd, "ALL")) { + what = QUERY_CPUS | QUERY_STOR | QUERY_DEVS; + } else if (!strcasecmp(cmd, "CPUS")) { + what = QUERY_CPUS; + } else if (!strcasecmp(cmd, "STOR") || + !strcasecmp(cmd, "STORA") || + !strcasecmp(cmd, "STORAG") || + !strcasecmp(cmd, "STORAGE")) { + what = QUERY_STOR; + } else { + cmd = __extract_hex(cmd, &devnum); + if (IS_ERR(cmd)) + return PTR_ERR(cmd); + + /* sch number must be: X'0000____' */ + if (devnum & ~0xffffull) + return -EINVAL; + + what = QUERY_DEVNUM; + } + + if (what & QUERY_CPUS) + __cmd_query_real_cpus(sys); + + if (what & QUERY_STOR) + __cmd_query_real_stor(sys); + + if (what & QUERY_DEVS) + list_devices(sys->con, display_rdev); + if (what & QUERY_DEVNUM) + con_printf(sys->con, "not implemented\n"); + + return 0; +} + +/* + *!!! QUERY TASK + *!! SYNTAX + *! \tok{\sc Query} \tok{\sc Task} + *!! XATNYS + *!! AUTH A + *!! PURPOSE + *! Lists all of the tasks running on the host. This includes guest virtual + *! cpu tasks, as well as system helper tasks. + */ +static int cmd_query_task(struct virt_sys *sys, char *cmd, int len) +{ + SHELL_CMD_AUTH(sys, 'A'); + + list_tasks(sys->con, display_task); + + return 0; +} + +static void display_names(struct console *con, struct virt_sys *sys) +{ + con_printf(con, "%s %04X %-8s\n", type2name(sys->con->dev->type), + sys->con->dev->ccuu, sys->directory->userid); +} + +/* + *!!! QUERY NAMES + *!! SYNTAX + *! \tok{\sc Query} \tok{\sc NAMes} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Lists all of the logged in users. + */ +static int cmd_query_names(struct virt_sys *sys, char *cmd, int len) +{ + list_users(sys->con, display_names); + + return 0; +} + +/* + *!!! QUERY USERID + *!! SYNTAX + *! \tok{\sc Query} \tok{\sc USERID} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Displays the current user id. + */ +static int cmd_query_userid(struct virt_sys *sys, char *cmd, int len) +{ + con_printf(sys->con, "%s\n", sys->directory->userid); + return 0; +} + +static struct cpcmd cmd_tbl_query[] = { + {"ARCHMODE", cmd_query_archmode, NULL}, + + {"CPLEVEL", cmd_query_cplevel, NULL}, + + {"TIME", cmd_query_time, NULL}, + + {"VIRTUAL", cmd_query_virtual, NULL}, + {"VIRTUA", cmd_query_virtual, NULL}, + {"VIRTU", cmd_query_virtual, NULL}, + {"VIRT", cmd_query_virtual, NULL}, + {"VIR", cmd_query_virtual, NULL}, + {"VI", cmd_query_virtual, NULL}, + {"V", cmd_query_virtual, NULL}, + + {"REAL", cmd_query_real, NULL}, + {"REA", cmd_query_real, NULL}, + {"RE", cmd_query_real, NULL}, + {"R", cmd_query_real, NULL}, + + {"NAMES", cmd_query_names, NULL}, + {"NAME", cmd_query_names, NULL}, + {"NAM", cmd_query_names, NULL}, + + {"TASK", cmd_query_task, NULL}, + + {"USERID", cmd_query_userid, NULL}, + {"", NULL, NULL}, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/cmd_set.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,42 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +/* + *!!! SET NOTS + *!! SYNTAX + *! \tok{\sc SET} \tok{\sc NOTS} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Disable the console timestamp printing + */ +static int cmd_set_nots(struct virt_sys *sys, char *cmd, int len) +{ + sys->print_ts = 0; + return 0; +} + +/* + *!!! SET TS + *!! SYNTAX + *! \tok{\sc SET} \tok{\sc TS} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Enable the console timestamp printing + */ +static int cmd_set_ts(struct virt_sys *sys, char *cmd, int len) +{ + sys->print_ts = 1; + return 0; +} + +static struct cpcmd cmd_tbl_set[] = { + {"NOTS", cmd_set_nots, NULL}, + {"TS", cmd_set_ts, NULL}, + {"", NULL, NULL}, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/cmd_store.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,355 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +/* + *!!! STORE STORAGE + *!! SYNTAX + *! \cbstart + *! \tok{\sc STOre} \tok{\sc STOrage} <address> <value> + *! \cbend + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Sets a word in guest's storage at address to value + */ +static int cmd_store_storage(struct virt_sys *sys, char *cmd, int len) +{ + int ret; + u64 guest_addr, host_addr; + u64 val = 0; + + cmd = parse_addrspec(&guest_addr, NULL, cmd); + if (IS_ERR(cmd)) { + con_printf(sys->con, "STORE: Invalid addr-spec\n"); + return PTR_ERR(cmd); + } + + /* consume any extra whitespace */ + cmd = __consume_ws(cmd); + + /* get the value */ + cmd = __extract_hex(cmd, &val); + if (IS_ERR(cmd)) + return PTR_ERR(cmd); + + /* + * round down to the nearest word + */ + guest_addr &= ~((u64) 3ULL); + + /* walk the page tables to find the real page frame */ + ret = virt2phy_current(guest_addr, &host_addr); + if (ret) { + con_printf(sys->con, "STORE: Specified address is not part of " + "guest configuration\n"); + return ret; + } + + *((u32*) host_addr) = (u32) val; + + con_printf(sys->con, "Store complete.\n"); + + return 0; +} + +/* + *!!! STORE GPR + *!! SYNTAX + *! \tok{\sc STOre} \tok{\sc Gpr} <gpr> <value> + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Sets a guest's general purpose register to the specified value + */ +static int cmd_store_gpr(struct virt_sys *sys, char *cmd, int len) +{ + u64 *ptr = (u64*) &sys->task->cpu->regs.gpr; + u64 val, gpr; + + cmd = __extract_dec(cmd, &gpr); + if (IS_ERR(cmd)) + return PTR_ERR(cmd); + if (gpr > 15) + return -EINVAL; + + cmd = __consume_ws(cmd); + + cmd = __extract_hex(cmd, &val); + if (IS_ERR(cmd)) + return PTR_ERR(cmd); + + ptr[gpr] = val; + + con_printf(sys->con, "Store complete.\n"); + + return 0; +} + +/* + *!!! STORE FPR + *!! SYNTAX + *! \tok{\sc STOre} \tok{\sc Fpr} <fpr> <value> + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Sets a guest's floating point register to the specified value + */ +static int cmd_store_fpr(struct virt_sys *sys, char *cmd, int len) +{ + u64 *ptr = (u64*) &sys->task->cpu->regs.fpr; + u64 val, fpr; + + cmd = __extract_dec(cmd, &fpr); + if (IS_ERR(cmd)) + return PTR_ERR(cmd); + if (fpr > 15) + return -EINVAL; + + cmd = __consume_ws(cmd); + + cmd = __extract_hex(cmd, &val); + if (IS_ERR(cmd)) + return PTR_ERR(cmd); + + ptr[fpr] = val; + + con_printf(sys->con, "Store complete.\n"); + + return 0; +} + +/* + *!!! STORE FPCR + *!! SYNTAX + *! \tok{\sc STOre} \tok{\sc FPCR} <value> + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Sets a guest's floating point control register to the specified value + */ +static int cmd_store_fpcr(struct virt_sys *sys, char *cmd, int len) +{ + u64 val; + + cmd = __extract_hex(cmd, &val); + if (IS_ERR(cmd)) + return PTR_ERR(cmd); + if (val > 0xffffffffULL) + return -EINVAL; + + sys->task->cpu->regs.fpcr = (u32) val; + + con_printf(sys->con, "Store complete.\n"); + + return 0; +} + +/* + *!!! STORE CR + *!! SYNTAX + *! \tok{\sc STOre} \tok{\sc Cr} <cr> <value> + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Sets a guest's control register to the specified value + */ +static int cmd_store_cr(struct virt_sys *sys, char *cmd, int len) +{ + u64 *ptr = (u64*) &sys->task->cpu->sie_cb.gcr; + u64 val, cr; + + cmd = __extract_dec(cmd, &cr); + if (IS_ERR(cmd)) + return PTR_ERR(cmd); + if (cr > 15) + return -EINVAL; + + cmd = __consume_ws(cmd); + + cmd = __extract_hex(cmd, &val); + if (IS_ERR(cmd)) + return PTR_ERR(cmd); + + ptr[cr] = val; + + con_printf(sys->con, "Store complete.\n"); + + return 0; +} + +/* + *!!! STORE AR + *!! SYNTAX + *! \tok{\sc STOre} \tok{\sc Ar} <ar> <value> + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Sets a guest's access register to the specified value + */ +static int cmd_store_ar(struct virt_sys *sys, char *cmd, int len) +{ + u32 *ptr = (u32*) &sys->task->cpu->regs.ar; + u64 val, ar; + + cmd = __extract_dec(cmd, &ar); + if (IS_ERR(cmd)) + return PTR_ERR(cmd); + if (ar > 15) + return -EINVAL; + + cmd = __consume_ws(cmd); + + cmd = __extract_hex(cmd, &val); + if (IS_ERR(cmd)) + return PTR_ERR(cmd); + if (val > 0xffffffffULL) + return -EINVAL; + + ptr[ar] = val; + + con_printf(sys->con, "Store complete.\n"); + + return 0; +} + +/* + *!!! STORE PSW + *!! SYNTAX + *! \cbstart + *! \tok{\sc STOre} \tok{\sc PSW} + *! \begin{stack} \\ + *! \begin{stack} \\ + *! \begin{stack} \\ <hexword1> + *! \end{stack} <hexword2> + *! \end{stack} <hexword3> + *! \end{stack} + *! <hexword4> + *! \cbend + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! \cbstart + *! Alters all or a part of the PSW. + *! \cbend + *!! OPERANDS + *! \cbstart + *! \item[hexword...] + *! \textbf{For an ESA/390 guest:} + *! + *! Alters all or part of the PSW with the data specified in hexword3 + *! and hexword4. If only hexword4 is specified, it is stored to PSW bits + *! 32-63. If hexword3 and hexword4 are specified, hexword3 is stored to + *! PSW bits 0-31, and hexword4 to PSW bits 32-63. + *! + *! If more than two values are specified, the PSW remains unchanged and an + *! message indicating an error is printed. + *! + *! \textbf{For a z/Architecture guest:} + *! + *! If only one hexword4 is specified, PSW bits 96-127 are set to it. + *! + *! If hexword3 and hexword4 are specified, PSW bits 64-95 are set to + *! hexword3, and bits 96-127 are set to hexword4. + *! + *! If hexword2, hexword3, and hexword4 are specified, PSW bits 32-63 are + *! set to hexword2, bits 64-95 are set to hexword3, and bits 96-127 are + *! set to hexword4. + *! + *! If hexword1, hexword2, hexword3, and hexword4 are specified, PSW bits + *! 0-31 are set to hexword1, bits 32-63 are set to hexword2, bits 64-95 + *! are set to hexword3, and bits 96-127 are set to hexword4. + *! \cbend + *!! SDNAREPO + */ +static int cmd_store_psw(struct virt_sys *sys, char *cmd, int len) +{ + u32 *ptr = (u32*) &sys->task->cpu->sie_cb.gpsw; + + u64 new_words[4] = {0, 0, 0, 0}; + int cnt; + + for (cnt=0; cnt<4; cnt++) { + cmd = __extract_hex(cmd, &new_words[cnt]); + if (IS_ERR(cmd)) + break; + + cmd = __consume_ws(cmd); + } + + if (!cnt) + return -EINVAL; + + if (!VCPU_ZARCH(sys->task->cpu)) { + /* ESA/390 mode */ + if (cnt > 2) { + con_printf(sys->con, "STORE: ERROR ESA/390 PSW USES ONLY TWO WORDS\n"); + return -EINVAL; + } + + /* + * This is a simple "hack" to make the stores go into the + * right place. If he had a single word, we want it to go + * the the second word of the 16-byte PSW, not the 4th. + * Similarly, if we had two words, we want them to go into + * the first and second words of the 16-byte PSW. + */ + cnt += 2; + } + + switch(cnt) { + case 4: + ptr[0] = (u32) new_words[0]; + ptr[1] = (u32) new_words[1]; + ptr[2] = (u32) new_words[2]; + ptr[3] = (u32) new_words[3]; + break; + case 3: + ptr[1] = (u32) new_words[0]; + ptr[2] = (u32) new_words[1]; + ptr[3] = (u32) new_words[2]; + break; + case 2: + ptr[2] = (u32) new_words[0]; + ptr[3] = (u32) new_words[1]; + break; + case 1: + ptr[3] = (u32) new_words[0]; + break; + case 0: + return -EINVAL; + } + + con_printf(sys->con, "Store complete.\n"); + return 0; +} + +static struct cpcmd cmd_tbl_store[] = { + {"AR", cmd_store_ar, NULL}, + {"A", cmd_store_ar, NULL}, + + {"CR", cmd_store_cr, NULL}, + {"C", cmd_store_cr, NULL}, + + {"FPCR", cmd_store_fpcr, NULL}, + + {"FPR", cmd_store_fpr, NULL}, + {"FP", cmd_store_fpr, NULL}, + {"F", cmd_store_fpr, NULL}, + + {"GPR", cmd_store_gpr, NULL}, + {"GP", cmd_store_gpr, NULL}, + {"G", cmd_store_gpr, NULL}, + + {"PSW", cmd_store_psw, NULL}, + + {"STORAGE", cmd_store_storage, NULL}, + {"STORAG", cmd_store_storage, NULL}, + {"STORA", cmd_store_storage, NULL}, + {"STOR", cmd_store_storage, NULL}, + {"STO", cmd_store_storage, NULL}, + {"", NULL, NULL}, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/cmd_system.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,156 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +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) +{ + struct virt_device *vdev; + u64 vdevnum = 0; + 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"); + + /* + * 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; +} + +/*!!! 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) +{ + 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; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/cmds.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,177 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <directory.h> +#include <vdevice.h> +#include <dat.h> +#include <mm.h> +#include <sched.h> +#include <disassm.h> +#include <cpu.h> +#include <vsprintf.h> +#include <shell.h> + +struct cpcmd { + const char name[SHELL_CMD_MAX_LEN]; + + /* handle function pointer */ + int (*fnx)(struct virt_sys *sys, char *cmd, int len); + + /* sub-command handler table */ + struct cpcmd *sub; +}; + +/* + * Map a device type to a nice to display name + */ +static char* type2name(u16 type) +{ + switch (type) { + case 0x1403: return "PRT"; + case 0x1732: return "OSA"; + case 0x3088: return "CTCA"; + case 0x3215: return "CONS"; + case 0x3278: return "GRAF"; + case 0x3505: return "RDR"; + case 0x3525: return "PUN"; + + /* various dasds */ + case 0x3390: + case 0x9336: return "DASD"; + + /* various tape drives */ + case 0x3480: + case 0x3490: + case 0x3590: return "TAPE"; + + default: return "????"; + } +} + +/* + * We use includes here to avoid namespace polution with all the sub-command + * 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_set.c" + +static struct cpcmd commands[] = { + {"BEGIN", cmd_begin, NULL}, + {"BEGI", cmd_begin, NULL}, + {"BEG", cmd_begin, NULL}, + {"BE", cmd_begin, NULL}, + + {"DISPLAY", NULL, cmd_tbl_display}, + {"DISPLA", NULL, cmd_tbl_display}, + {"DISPL", NULL, cmd_tbl_display}, + {"DISP", NULL, cmd_tbl_display}, + {"DIS", NULL, cmd_tbl_display}, + {"DI", NULL, cmd_tbl_display}, + {"D", NULL, cmd_tbl_display}, + + {"ENABLE", cmd_enable, NULL}, + {"ENABL", cmd_enable, NULL}, + {"ENAB", cmd_enable, NULL}, + {"ENA", cmd_enable, NULL}, + + {"IPL", cmd_ipl, NULL}, + {"IP", cmd_ipl, NULL}, + {"I", cmd_ipl, NULL}, + + {"LOGON", cmd_logon_fail, NULL}, + {"LOGO", cmd_logon_fail, NULL}, + {"LOG", cmd_logon_fail, NULL}, + {"LO", cmd_logon_fail, NULL}, + {"L", cmd_logon_fail, NULL}, + + {"QUERY", NULL, cmd_tbl_query}, + {"QUER", NULL, cmd_tbl_query}, + {"QUE", NULL, cmd_tbl_query}, + {"QU", NULL, cmd_tbl_query}, + {"Q", NULL, cmd_tbl_query}, + + {"SET", NULL, cmd_tbl_set}, + + {"STOP", cmd_stop, NULL}, + + {"STORE", NULL, cmd_tbl_store}, + {"STOR", NULL, cmd_tbl_store}, + {"STO", NULL, cmd_tbl_store}, + + {"SYSTEM", cmd_system, NULL}, + {"SYSTE", cmd_system, NULL}, + {"SYST", cmd_system, NULL}, + {"SYS", cmd_system, NULL}, + {"", NULL, NULL}, +}; + +static struct cpcmd logon_commands[] = { + {"LOGON", 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) +{ + int i, ret; + + for(i=0; t[i].name[0]; i++) { + const char *inp = cmd, *exp = t[i].name; + int match_len = 0; + + while(*inp && *exp && (match_len < len) && (toupper(*inp) == *exp)) { + match_len++; + inp++; + exp++; + } + + /* doesn't match */ + if ((match_len != strnlen(t[i].name, SHELL_CMD_MAX_LEN)) || + (!isspace(*inp) && *inp)) + continue; + + /* + * the next char in the input is... + */ + while((cmd[match_len] == ' ' || cmd[match_len] == '\t') && + (match_len < len)) + /* + * command was given arguments - skip over the + * delimiting space + */ + match_len++; + + if (t[i].sub) { + ret = __invoke_shell_cmd(t[i].sub, sys, cmd + match_len, len - match_len); + return (ret == -ENOENT) ? -ESUBENOENT : ret; + } + + return t[i].fnx(sys, cmd + match_len, len - match_len); + } + + return -ENOENT; +} + +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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/directory.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,27 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <errno.h> +#include <directory.h> + +#include "directory_structs.c" + +struct user *find_user_by_id(char *userid) +{ + struct user *u; + + if (!userid) + return ERR_PTR(-ENOENT); + + u = directory; + + for (; u->userid; u++) + if (!strcasecmp(u->userid, userid)) + return u; + + return ERR_PTR(-ENOENT); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/disassm.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,1098 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <disassm.h> +#include <vsprintf.h> + +static struct disassm_instruction l2_01[256] = { /* 01xx */ + DA_INST (0x01, E, PR), + DA_INST (0x02, E, UPT), + DA_INST (0x04, E, PTFF), + DA_INST (0x07, E, SCKPF), + DA_INST (0x0A, E, PFPO), + DA_INST (0x0B, E, TAM), + DA_INST (0x0C, E, SAM24), + DA_INST (0x0D, E, SAM31), + DA_INST (0x0E, E, SAM64), + DA_INST (0xFF, E, TRAP2), +}; + +static struct disassm_instruction l2_a5[16] = { /* A5x */ + DA_INST (0x0, RI1, IIHH), + DA_INST (0x1, RI1, IIHL), + DA_INST (0x2, RI1, IILH), + DA_INST (0x3, RI1, IILL), + DA_INST (0x4, RI1, NIHH), + DA_INST (0x5, RI1, NIHL), + DA_INST (0x6, RI1, NILH), + DA_INST (0x7, RI1, NILL), + DA_INST (0x8, RI1, OIHH), + DA_INST (0x9, RI1, OIHL), + DA_INST (0xA, RI1, OILH), + DA_INST (0xB, RI1, OILL), + DA_INST (0xC, RI1, LLIHH), + DA_INST (0xD, RI1, LLIHL), + DA_INST (0xE, RI1, LLILH), + DA_INST (0xF, RI1, LLILL), +}; + +static struct disassm_instruction l2_a7[16] = { /* A7x */ + DA_INST (0x0, RI1, TMLH), + DA_INST (0x1, RI1, TMLL), + DA_INST (0x2, RI1, TMHH), + DA_INST (0x3, RI1, TMHL), + DA_INST (0x4, RI2, BRC), + DA_INST (0x5, RI1, BRAS), + DA_INST (0x6, RI1, BRCT), + DA_INST (0x7, RI1, BRCTG), + DA_INST (0x8, RI1, LHI), + DA_INST (0x9, RI1, LGHI), + DA_INST (0xA, RI1, AHI), + DA_INST (0xB, RI1, AGHI), + DA_INST (0xC, RI1, MHI), + DA_INST (0xD, RI1, MGHI), + DA_INST (0xE, RI1, CHI), + DA_INST (0xF, RI1, CGHI), +}; + +static struct disassm_instruction l2_b2[256] = { /* B2xx */ + DA_INST (0x02, S, STIDP), + DA_INST (0x04, S, SCK), + DA_INST (0x05, S, STCK), + DA_INST (0x06, S, SCKC), + DA_INST (0x07, S, STCKC), + DA_INST (0x08, S, SPT), + DA_INST (0x09, S, STPT), + DA_INST (0x0A, S, SPKA), + DA_INST (0x0B, S, IPK), + DA_INST (0x0D, S, PTLB), + DA_INST (0x10, S, SPX), + DA_INST (0x11, S, STPX), + DA_INST (0x12, S, STAP), + DA_INST (0x14, S, SIE), + DA_INST (0x18, S, PC), + DA_INST (0x19, S, SAC), + DA_INST (0x1A, S, CFC), + DA_INST (0x21, RRE, IPTE), + DA_INST (0x22, RRE, IPM), + DA_INST (0x23, RRE, IVSK), + DA_INST (0x24, RRE, IAC), + DA_INST (0x25, RRE, SSAR), + DA_INST (0x26, RRE, EPAR), + DA_INST (0x27, RRE, ESAR), + DA_INST (0x28, RRE, PT), + DA_INST (0x29, RRE, ISKE), + DA_INST (0x2A, RRE, RRBE), + DA_INST (0x2B, RRF2, SSKE), + DA_INST (0x2C, RRE, TB), + DA_INST (0x2D, RRE, DXR), + DA_INST (0x2E, RRE, PGIN), + DA_INST (0x2F, RRE, PGOUT), + DA_INST (0x30, S, CSCH), + DA_INST (0x31, S, HSCH), + DA_INST (0x32, S, MSCH), + DA_INST (0x33, S, SSCH), + DA_INST (0x34, S, STSCH), + DA_INST (0x35, S, TSCH), + DA_INST (0x36, S, TPI), + DA_INST (0x37, S, SAL), + DA_INST (0x38, S, RSCH), + DA_INST (0x39, S, STCRW), + DA_INST (0x3A, S, STCPS), + DA_INST (0x3B, S, RCHP), + DA_INST (0x3D, S, SCHM), + DA_INST (0x40, RRE, BAKR), + DA_INST (0x41, RRE, CKSM), + DA_INST (0x44, RRE, SQDR), + DA_INST (0x45, RRE, SQER), + DA_INST (0x46, RRE, STURA), + DA_INST (0x47, RRE, MSTA), + DA_INST (0x48, RRE, PALB), + DA_INST (0x49, RRE, EREG), + DA_INST (0x4A, RRE, ESTA), + DA_INST (0x4B, RRE, LURA), + DA_INST (0x4C, RRE, TAR), + DA_INST (0x4D, RRE, CPYA), + DA_INST (0x4E, RRE, SAR), + DA_INST (0x4F, RRE, EAR), + DA_INST (0x50, RRE, CSP), + DA_INST (0x52, RRE, MSR), + DA_INST (0x54, RRE, MVPG), + DA_INST (0x55, RRE, MVST), + DA_INST (0x57, RRE, CUSE), + DA_INST (0x58, RRE, BSG), + DA_INST (0x5A, RRE, BSA), + DA_INST (0x5D, RRE, CLST), + DA_INST (0x5E, RRE, SRST), + DA_INST (0x63, RRE, CMPSC), + DA_INST (0x76, S, XSCH), + DA_INST (0x77, S, RP), + DA_INST (0x78, S, STCKE), + DA_INST (0x79, S, SACF), + DA_INST (0x7C, S, STCKF), + DA_INST (0x7D, S, STSI), + DA_INST (0x99, S, SRNM), + DA_INST (0x9C, S, STFPC), + DA_INST (0x9D, S, LFPC), + DA_INST (0xA5, RRE, TRE), + DA_INST (0xA6, RRF2, CUUTF), + DA_INST (0xA7, RRF2, CUTFU), + DA_INST (0xB0, S, STFLE), + DA_INST (0xB1, S, STFL), + DA_INST (0xB2, S, LPSWE), + DA_INST (0xB9, S, SRNMT), + DA_INST (0xBD, S, LFAS), + DA_INST (0xFF, S, TRAP4), +}; + +static struct disassm_instruction l2_b3[256] = { /* B3xx */ + DA_INST (0x00, RRE, LPEBR), + DA_INST (0x01, RRE, LNEBR), + DA_INST (0x02, RRE, LTEBR), + DA_INST (0x03, RRE, LCEBR), + DA_INST (0x04, RRE, LDEBR), + DA_INST (0x05, RRE, LXDBR), + DA_INST (0x06, RRE, LXEBR), + DA_INST (0x07, RRE, MXDBR), + DA_INST (0x08, RRE, KEBR), + DA_INST (0x09, RRE, CEBR), + DA_INST (0x0A, RRE, AEBR), + DA_INST (0x0B, RRE, SEBR), + DA_INST (0x0C, RRE, MDEBR), + DA_INST (0x0D, RRE, DEBR), + DA_INST (0x0E, RRF1, MAEBR), + DA_INST (0x0F, RRF1, MSEBR), + DA_INST (0x10, RRE, LPDBR), + DA_INST (0x11, RRE, LNDBR), + DA_INST (0x12, RRE, LTDBR), + DA_INST (0x13, RRE, LCDBR), + DA_INST (0x14, RRE, SQEBR), + DA_INST (0x15, RRE, SQDBR), + DA_INST (0x16, RRE, SQXBR), + DA_INST (0x17, RRE, MEEBR), + DA_INST (0x18, RRE, KDBR), + DA_INST (0x19, RRE, CDBR), + DA_INST (0x1A, RRE, ADBR), + DA_INST (0x1B, RRE, SDBR), + DA_INST (0x1C, RRE, MDBR), + DA_INST (0x1D, RRE, DDBR), + DA_INST (0x1E, RRF1, MADBR), + DA_INST (0x1F, RRF1, MSDBR), + DA_INST (0x24, RRE, LDER), + DA_INST (0x25, RRE, LXDR), + DA_INST (0x26, RRE, LXER), + DA_INST (0x2E, RRF1, MAER), + DA_INST (0x2F, RRF1, MSER), + DA_INST (0x36, RRE, SQXR), + DA_INST (0x37, RRE, MEER), + DA_INST (0x38, RRF1, MAYLR), + DA_INST (0x39, RRF1, MYLR), + DA_INST (0x3A, RRF1, MAYR), + DA_INST (0x3B, RRF1, MYR), + DA_INST (0x3C, RRF1, MAYHR), + DA_INST (0x3D, RRF1, MYHR), + DA_INST (0x3E, RRF1, MADR), + DA_INST (0x3F, RRF1, MSDR), + DA_INST (0x40, RRE, LPXBR), + DA_INST (0x41, RRE, LNXBR), + DA_INST (0x42, RRE, LTXBR), + DA_INST (0x43, RRE, LCXBR), + DA_INST (0x44, RRE, LEDBR), + DA_INST (0x45, RRE, LDXBR), + DA_INST (0x46, RRE, LEXBR), + DA_INST (0x47, RRF2, FIXBR), + DA_INST (0x48, RRE, KXBR), + DA_INST (0x49, RRE, CXBR), + DA_INST (0x4A, RRE, AXBR), + DA_INST (0x4B, RRE, SXBR), + DA_INST (0x4C, RRE, MXBR), + DA_INST (0x4D, RRE, DXBR), + DA_INST (0x50, RRF2, TBEDR), + DA_INST (0x51, RRF2, TBDR), + DA_INST (0x53, RRF3, DIEBR), + DA_INST (0x57, RRF2, FIEBR), + DA_INST (0x58, RRE, THDER), + DA_INST (0x59, RRE, THDR), + DA_INST (0x5B, RRF3, DIDBR), + DA_INST (0x5F, RRF2, FIDBR), + DA_INST (0x60, RRE, LPXR), + DA_INST (0x61, RRE, LNXR), + DA_INST (0x62, RRE, LTXR), + DA_INST (0x63, RRE, LCXR), + DA_INST (0x65, RRE, LXR), + DA_INST (0x66, RRE, LEXR), + DA_INST (0x67, RRE, FIXR), + DA_INST (0x69, RRE, CXR), + DA_INST (0x70, RRE, LPDFR), + DA_INST (0x71, RRE, LNDFR), + DA_INST (0x72, RRF1, CPSDR), + DA_INST (0x73, RRE, LCDFR), + DA_INST (0x74, RRE, LZER), + DA_INST (0x75, RRE, LZDR), + DA_INST (0x76, RRE, LZXR), + DA_INST (0x77, RRE, FIER), + DA_INST (0x7F, RRE, FIDR), + DA_INST (0x84, RRE, SFPC), + DA_INST (0x85, RRE, SFASR), + DA_INST (0x8C, RRE, EFPC), + DA_INST (0x94, RRE, CEFBR), + DA_INST (0x95, RRE, CDFBR), + DA_INST (0x96, RRE, CXFBR), + DA_INST (0x98, RRF2, CFEBR), + DA_INST (0x99, RRF2, CFDBR), + DA_INST (0x9A, RRF2, CFXBR), + DA_INST (0xA4, RRE, CEGBR), + DA_INST (0xA5, RRE, CDGBR), + DA_INST (0xA6, RRE, CXGBR), + DA_INST (0xA8, RRF2, CGEBR), + DA_INST (0xA9, RRF2, CGDBR), + DA_INST (0xAA, RRF2, CGXBR), + DA_INST (0xB4, RRE, CEFR), + DA_INST (0xB5, RRE, CDFR), + DA_INST (0xB6, RRE, CXFR), + DA_INST (0xB8, RRF2, CFER), + DA_INST (0xB9, RRF2, CFDR), + DA_INST (0xBA, RRF2, CFXR), + DA_INST (0xC1, RRE, LDGR), + DA_INST (0xC4, RRE, CEGR), + DA_INST (0xC5, RRE, CDGR), + DA_INST (0xC6, RRE, CXGR), + DA_INST (0xC8, RRF2, CGER), + DA_INST (0xC9, RRF2, CGDR), + DA_INST (0xCA, RRF2, CGXR), + DA_INST (0xCD, RRE, LGDR), + DA_INST (0xD0, RRR, MDTR), + DA_INST (0xD1, RRR, DDTR), + DA_INST (0xD2, RRR, ADTR), + DA_INST (0xD3, RRR, SDTR), + DA_INST (0xD4, RRF3, LDETR), + DA_INST (0xD5, RRF3, LEDTR), + DA_INST (0xD6, RRE, LTDTR), + DA_INST (0xD7, RRF3, FIDTR), + DA_INST (0xD8, RRR, MXTR), + DA_INST (0xD9, RRR, DXTR), + DA_INST (0xDA, RRR, AXTR), + DA_INST (0xDB, RRR, SXTR), + DA_INST (0xDC, RRF3, LXDTR), + DA_INST (0xDD, RRF3, LDXTR), + DA_INST (0xDE, RRE, LTXTR), + DA_INST (0xDF, RRF3, FIXTR), + DA_INST (0xE0, RRE, KDTR), + DA_INST (0xE1, RRF2, CGDTR), + DA_INST (0xE2, RRE, CUDTR), + DA_INST (0xE3, RRF3, CSDTR), + DA_INST (0xE4, RRE, CDTR), + DA_INST (0xE5, RRE, EEDTR), + DA_INST (0xE7, RRE, ESDTR), + DA_INST (0xE8, RRE, KXTR), + DA_INST (0xE9, RRF2, CGXTR), + DA_INST (0xEA, RRE, CUXTR), + DA_INST (0xEB, RRF3, CSXTR), + DA_INST (0xEC, RRE, CXTR), + DA_INST (0xED, RRE, EEXTR), + DA_INST (0xEF, RRE, ESXTR), + DA_INST (0xF1, RRE, CDGTR), + DA_INST (0xF2, RRE, CDUTR), + DA_INST (0xF3, RRE, CDSTR), + DA_INST (0xF4, RRE, CEDTR), + DA_INST (0xF5, RRF3, QADTR), + DA_INST (0xF6, RRF3, IEDTR), + DA_INST (0xF7, RRF3, RRDTR), + DA_INST (0xF9, RRE, CXGTR), + DA_INST (0xFA, RRE, CXUTR), + DA_INST (0xFB, RRE, CXSTR), + DA_INST (0xFC, RRE, CEXTR), + DA_INST (0xFD, RRF3, QAXTR), + DA_INST (0xFE, RRF3, IEXTR), + DA_INST (0xFF, RRF3, RRXTR), +}; + +static struct disassm_instruction l2_b9[256] = { /* B9xx */ + DA_INST (0x00, RRE, LPGR), + DA_INST (0x01, RRE, LNGR), + DA_INST (0x02, RRE, LTGR), + DA_INST (0x03, RRE, LCGR), + DA_INST (0x04, RRE, LGR), + DA_INST (0x05, RRE, LURAG), + DA_INST (0x06, RRE, LGBR), + DA_INST (0x07, RRE, LGHR), + DA_INST (0x08, RRE, AGR), + DA_INST (0x09, RRE, SGR), + DA_INST (0x0A, RRE, ALGR), + DA_INST (0x0B, RRE, SLGR), + DA_INST (0x0C, RRE, MSGR), + DA_INST (0x0D, RRE, DSGR), + DA_INST (0x0E, RRE, EREGG), + DA_INST (0x0F, RRE, LRVGR), + DA_INST (0x10, RRE, LPGFR), + DA_INST (0x11, RRE, LNGFR), + DA_INST (0x12, RRE, LTGFR), + DA_INST (0x13, RRE, LCGFR), + DA_INST (0x14, RRE, LGFR), + DA_INST (0x16, RRE, LLGFR), + DA_INST (0x17, RRE, LLGTR), + DA_INST (0x18, RRE, AGFR), + DA_INST (0x19, RRE, SGFR), + DA_INST (0x1A, RRE, ALGFR), + DA_INST (0x1B, RRE, SLGFR), + DA_INST (0x1C, RRE, MSGFR), + DA_INST (0x1D, RRE, DSGFR), + DA_INST (0x1E, RRE, KMAC), + DA_INST (0x1F, RRE, LRVR), + DA_INST (0x20, RRE, CGR), + DA_INST (0x21, RRE, CLGR), + DA_INST (0x25, RRE, STURG), + DA_INST (0x26, RRE, LBR), + DA_INST (0x27, RRE, LHR), + DA_INST (0x2E, RRE, KM), + DA_INST (0x2F, RRE, KMC), + DA_INST (0x30, RRE, CGFR), + DA_INST (0x31, RRE, CLGFR), + DA_INST (0x3E, RRE, KIMD), + DA_INST (0x3F, RRE, KLMD), + DA_INST (0x46, RRE, BCTGR), + DA_INST (0x60, RRF2, CGRT), + DA_INST (0x61, RRF2, CLGRT), + DA_INST (0x72, RRF2, CRT), + DA_INST (0x73, RRF2, CLRT), + DA_INST (0x80, RRE, NGR), + DA_INST (0x81, RRE, OGR), + DA_INST (0x82, RRE, XGR), + DA_INST (0x83, RRE, FLOGR), + DA_INST (0x84, RRE, LLGCR), + DA_INST (0x85, RRE, LLGHR), + DA_INST (0x86, RRE, MLGR), + DA_INST (0x87, RRE, DLGR), + DA_INST (0x88, RRE, ALCGR), + DA_INST (0x89, RRE, SLBGR), + DA_INST (0x8A, RRE, CSPG), + DA_INST (0x8D, RRE, EPSW), + DA_INST (0x8E, RRF3, IDTE), + DA_INST (0x90, RRF2, TRTT), + DA_INST (0x91, RRF2, TRTO), + DA_INST (0x92, RRF2, TROT), + DA_INST (0x93, RRF2, TROO), + DA_INST (0x94, RRE, LLCR), + DA_INST (0x95, RRE, LLHR), + DA_INST (0x96, RRE, MLR), + DA_INST (0x97, RRE, DLR), + DA_INST (0x98, RRE, ALCR), + DA_INST (0x99, RRE, SLBR), + DA_INST (0x9A, RRE, EPAIR), + DA_INST (0x9B, RRE, ESAIR), + DA_INST (0x9D, RRE, ESEA), + DA_INST (0x9E, RRE, PTI), + DA_INST (0x9F, RRE, SSAIR), + DA_INST (0xA2, RRE, PTF), + DA_INST (0xAA, RRF3, LPTEA), + DA_INST (0xAF, RRE, PFMF), + DA_INST (0xB0, RRF2, CU14), + DA_INST (0xB1, RRF2, CU24), + DA_INST (0xB2, RRE, CU41), + DA_INST (0xB3, RRE, CU42), + DA_INST (0xBD, RRF2, TRTRE), + DA_INST (0xBE, RRE, SRSTU), + DA_INST (0xBF, RRF2, TRTE), +}; + +static struct disassm_instruction l2_c0[16] = { /* C0x */ + DA_INST (0x0, RIL1, LARL), + DA_INST (0x1, RIL1, LGFI), + DA_INST (0x4, RIL2, BRCL), + DA_INST (0x5, RIL1, BRASL), + DA_INST (0x6, RIL1, XIHF), + DA_INST (0x7, RIL1, XILF), + DA_INST (0x8, RIL1, IIHF), + DA_INST (0x9, RIL1, IILF), + DA_INST (0xA, RIL1, NIHF), + DA_INST (0xB, RIL1, NILF), + DA_INST (0xC, RIL1, OIHF), + DA_INST (0xD, RIL1, OILF), + DA_INST (0xE, RIL1, LLIHF), + DA_INST (0xF, RIL1, LLILF), +}; + +static struct disassm_instruction l2_c2[16] = { /* C2x */ + DA_INST (0x0, RIL1, MSGFI), + DA_INST (0x1, RIL1, MSFI), + DA_INST (0x4, RIL1, SLGFI), + DA_INST (0x5, RIL1, SLFI), + DA_INST (0x8, RIL1, AGFI), + DA_INST (0x9, RIL1, AFI), + DA_INST (0xA, RIL1, ALGFI), + DA_INST (0xB, RIL1, ALFI), + DA_INST (0xC, RIL1, CGFI), + DA_INST (0xD, RIL1, CFI), + DA_INST (0xE, RIL1, CLGFI), + DA_INST (0xF, RIL1, CLFI), +}; + +static struct disassm_instruction l2_c4[16] = { /* C4x */ + DA_INST (0x2, RIL1, LLHRL), + DA_INST (0x4, RIL1, LGHRL), + DA_INST (0x5, RIL1, LHRL), + DA_INST (0x6, RIL1, LLGHRL), + DA_INST (0x7, RIL1, STHRL), + DA_INST (0x8, RIL1, LGRL), + DA_INST (0xB, RIL1, STGRL), + DA_INST (0xC, RIL1, LGFRL), + DA_INST (0xD, RIL1, LRL), + DA_INST (0xE, RIL1, LLGFRL), + DA_INST (0xF, RIL1, STRL), +}; + +static struct disassm_instruction l2_c6[16] = { /* C6x */ + DA_INST (0x0, RIL1, EXRL), + DA_INST (0x2, RIL2, PFDRL), + DA_INST (0x4, RIL1, CGHRL), + DA_INST (0x5, RIL1, CHRL), + DA_INST (0x6, RIL1, CLGHRL), + DA_INST (0x7, RIL1, CLHRL), + DA_INST (0x8, RIL1, CGRL), + DA_INST (0xA, RIL1, CLGRL), + DA_INST (0xC, RIL1, CGFRL), + DA_INST (0xD, RIL1, CRL), + DA_INST (0xE, RIL1, CLGFRL), + DA_INST (0xF, RIL1, CLRL), +}; + +static struct disassm_instruction l2_c8[16] = { /* C8x */ + DA_INST (0x0, SSF, MVCOS), + DA_INST (0x1, SSF, ECTG), + DA_INST (0x2, SSF, CSST), +}; + +static struct disassm_instruction l2_e3[256] = { /* E3xx */ + DA_INST (0x02, RXY, LTG), + DA_INST (0x03, RXY, LRAG), + DA_INST (0x04, RXY, LG), + DA_INST (0x06, RXY, CVBY), + DA_INST (0x08, RXY, AG), + DA_INST (0x09, RXY, SG), + DA_INST (0x0A, RXY, ALG), + DA_INST (0x0B, RXY, SLG), + DA_INST (0x0C, RXY, MSG), + DA_INST (0x0D, RXY, DSG), + DA_INST (0x0E, RXY, CVBG), + DA_INST (0x0F, RXY, LRVG), + DA_INST (0x12, RXY, LT), + DA_INST (0x13, RXY, LRAY), + DA_INST (0x14, RXY, LGF), + DA_INST (0x15, RXY, LGH), + DA_INST (0x16, RXY, LLGF), + DA_INST (0x17, RXY, LLGT), + DA_INST (0x18, RXY, AGF), + DA_INST (0x19, RXY, SGF), + DA_INST (0x1A, RXY, ALGF), + DA_INST (0x1B, RXY, SLGF), + DA_INST (0x1C, RXY, MSGF), + DA_INST (0x1D, RXY, DSGF), + DA_INST (0x1E, RXY, LRV), + DA_INST (0x1F, RXY, LRVH), + DA_INST (0x20, RXY, CG), + DA_INST (0x21, RXY, CLG), + DA_INST (0x24, RXY, STG), + DA_INST (0x26, RXY, CVDY), + DA_INST (0x2E, RXY, CVDG), + DA_INST (0x2F, RXY, STRVG), + DA_INST (0x30, RXY, CGF), + DA_INST (0x31, RXY, CLGF), + DA_INST (0x32, RXY, LTGF), + DA_INST (0x34, RXY, CGH), + DA_INST (0x36, RXY, PFD), + DA_INST (0x3E, RXY, STRV), + DA_INST (0x3F, RXY, STRVH), + DA_INST (0x46, RXY, BCTG), + DA_INST (0x50, RXY, STY), + DA_INST (0x51, RXY, MSY), + DA_INST (0x54, RXY, NY), + DA_INST (0x55, RXY, CLY), + DA_INST (0x56, RXY, OY), + DA_INST (0x57, RXY, XY), + DA_INST (0x58, RXY, LY), + DA_INST (0x59, RXY, CY), + DA_INST (0x5A, RXY, AY), + DA_INST (0x5B, RXY, SY), + DA_INST (0x5C, RXY, MFY), + DA_INST (0x5E, RXY, ALY), + DA_INST (0x5F, RXY, SLY), + DA_INST (0x70, RXY, STHY), + DA_INST (0x71, RXY, LAY), + DA_INST (0x72, RXY, STCY), + DA_INST (0x73, RXY, ICY), + DA_INST (0x75, RXY, LAEY), + DA_INST (0x76, RXY, LB), + DA_INST (0x77, RXY, LGB), + DA_INST (0x78, RXY, LHY), + DA_INST (0x79, RXY, CHY), + DA_INST (0x7A, RXY, AHY), + DA_INST (0x7B, RXY, SHY), + DA_INST (0x7C, RXY, MHY), + DA_INST (0x80, RXY, NG), + DA_INST (0x81, RXY, OG), + DA_INST (0x82, RXY, XG), + DA_INST (0x86, RXY, MLG), + DA_INST (0x87, RXY, DLG), + DA_INST (0x88, RXY, ALCG), + DA_INST (0x89, RXY, SLBG), + DA_INST (0x8E, RXY, STPQ), + DA_INST (0x8F, RXY, LPQ), + DA_INST (0x90, RXY, LLGC), + DA_INST (0x91, RXY, LLGH), + DA_INST (0x94, RXY, LLC), + DA_INST (0x95, RXY, LLH), + DA_INST (0x96, RXY, ML), + DA_INST (0x97, RXY, DL), + DA_INST (0x98, RXY, ALC), + DA_INST (0x99, RXY, SLB), +}; + +static struct disassm_instruction l2_e5[256] = { /* E5xx */ + DA_INST (0x00, SSE, LASP), + DA_INST (0x01, SSE, TPROT), + DA_INST (0x02, SSE, STRAG), + DA_INST (0x0E, SSE, MVCSK), + DA_INST (0x0F, SSE, MVCDK), + DA_INST (0x44, SIL, MVHHI), + DA_INST (0x48, SIL, MVGHI), + DA_INST (0x4C, SIL, MVHI), + DA_INST (0x54, SIL, CHHSI), + DA_INST (0x55, SIL, CLHHSI), + DA_INST (0x58, SIL, CGHSI), + DA_INST (0x59, SIL, CLGHSI), + DA_INST (0x5C, SIL, CHSI), + DA_INST (0x5D, SIL, CLFHSI), +}; + +static struct disassm_instruction l2_eb[256] = { /* EBxx */ + DA_INST (0x04, RSY1, LMG), + DA_INST (0x0A, RSY1, SRAG), + DA_INST (0x0B, RSY1, SLAG), + DA_INST (0x0C, RSY1, SRLG), + DA_INST (0x0D, RSY1, SLLG), + DA_INST (0x0F, RSY1, TRACG), + DA_INST (0x14, RSY1, CSY), + DA_INST (0x1C, RSY1, RLLG), + DA_INST (0x1D, RSY1, RLL), + DA_INST (0x20, RSY2, CLMH), + DA_INST (0x21, RSY2, CLMY), + DA_INST (0x24, RSY1, STMG), + DA_INST (0x25, RSY1, STCTG), + DA_INST (0x26, RSY1, STMH), + DA_INST (0x2C, RSY2, STCMH), + DA_INST (0x2D, RSY2, STCMY), + DA_INST (0x2F, RSY1, LCTLG), + DA_INST (0x30, RSY1, CSG), + DA_INST (0x31, RSY1, CDSY), + DA_INST (0x3E, RSY1, CDSG), + DA_INST (0x44, RSY1, BXHG), + DA_INST (0x45, RSY1, BXLEG), + DA_INST (0x4C, RSY1, ECAG), + DA_INST (0x51, SIY, TMY), + DA_INST (0x52, SIY, MVIY), + DA_INST (0x54, SIY, NIY), + DA_INST (0x55, SIY, CLIY), + DA_INST (0x56, SIY, OIY), + DA_INST (0x57, SIY, XIY), + DA_INST (0x6A, SIY, ASI), + DA_INST (0x6E, SIY, ALSI), + DA_INST (0x80, RSY2, ICMH), + DA_INST (0x81, RSY2, ICMY), + DA_INST (0x8E, RSY1, MVCLU), + DA_INST (0x8F, RSY1, CLCLU), + DA_INST (0x90, RSY1, STMY), + DA_INST (0x96, RSY1, LMH), + DA_INST (0x98, RSY1, LMY), + DA_INST (0x9A, RSY1, LAMY), + DA_INST (0x9B, RSY1, STAMY), + DA_INST (0xC0, RSL, TP), +}; + +static struct disassm_instruction l2_ec[256] = { /* ECxx */ + DA_INST (0x44, RIE, BRXHG), + DA_INST (0x45, RIE, BRXLG), + DA_INST (0x54, RIE, RNSBG), + DA_INST (0x55, RIE, RISBG), + DA_INST (0x56, RIE, ROSBG), + DA_INST (0x57, RIE, RXSBG), + DA_INST (0x64, RIE, CGRJ), + DA_INST (0x65, RIE, CLGRJ), + DA_INST (0x70, RIE, CGIT), + DA_INST (0x71, RIE, CLGIT), + DA_INST (0x72, RIE, CIT), + DA_INST (0x73, RIE, CLFIT), + DA_INST (0x76, RIE, CRJ), + DA_INST (0x77, RIE, CLRJ), + DA_INST (0x7C, RIE, CGIJ), + DA_INST (0x7D, RIE, CLGIJ), + DA_INST (0x7E, RIE, CIJ), + DA_INST (0x7F, RIE, CLIJ), + DA_INST (0xE4, RRS, CGRB), + DA_INST (0xE5, RRS, CLGRB), + DA_INST (0xF6, RRS, CRB), + DA_INST (0xF7, RRS, CLRB), + DA_INST (0xFC, RIS, CGIB), + DA_INST (0xFD, RIS, CLGIB), +}; + +static struct disassm_instruction l2_ed[256] = { /* EDxx */ + DA_INST (0x04, RXE, LDEB), + DA_INST (0x05, RXE, LXDB), + DA_INST (0x06, RXE, LXEB), + DA_INST (0x07, RXE, MXDB), + DA_INST (0x08, RXE, KEB), + DA_INST (0x09, RXE, CEB), + DA_INST (0x0A, RXE, AEB), + DA_INST (0x0B, RXE, SEB), + DA_INST (0x0C, RXE, MDEB), + DA_INST (0x0D, RXE, DEB), + DA_INST (0x0E, RXE, MAEB), + DA_INST (0x0F, RXE, MSEB), + DA_INST (0x10, RXE, TCEB), + DA_INST (0x11, RXE, TCDB), + DA_INST (0x12, RXE, TCXB), + DA_INST (0x14, RXE, SQEB), + DA_INST (0x15, RXE, SQDB), + DA_INST (0x17, RXE, MEEB), + DA_INST (0x18, RXE, KDB), + DA_INST (0x19, RXE, CDB), + DA_INST (0x1A, RXE, ADB), + DA_INST (0x1B, RXE, SDB), + DA_INST (0x1C, RXE, MDB), + DA_INST (0x1D, RXE, DDB), + DA_INST (0x1E, RXF, MADB), + DA_INST (0x1F, RXF, MSDB), + DA_INST (0x24, RXE, LDE), + DA_INST (0x25, RXE, LXD), + DA_INST (0x26, RXE, LXE), + DA_INST (0x2E, RXF, MAE), + DA_INST (0x2F, RXF, MSE), + DA_INST (0x34, RXE, SQE), + DA_INST (0x35, RXE, SQD), + DA_INST (0x37, RXE, MEE), + DA_INST (0x38, RXF, MAYL), + DA_INST (0x39, RXF, MYL), + DA_INST (0x3A, RXF, MAY), + DA_INST (0x3B, RXF, MY), + DA_INST (0x3C, RXF, MAYH), + DA_INST (0x3D, RXF, MYH), + DA_INST (0x3E, RXF, MAD), + DA_INST (0x3F, RXF, MSD), + DA_INST (0x40, RXF, SLDT), + DA_INST (0x41, RXF, SRDT), + DA_INST (0x48, RXF, SLXT), + DA_INST (0x49, RXF, SRXT), + DA_INST (0x50, RXE, TDCET), + DA_INST (0x51, RXE, TDGET), + DA_INST (0x54, RXE, TDCDT), + DA_INST (0x55, RXE, TDGDT), + DA_INST (0x58, RXE, TDCXT), + DA_INST (0x59, RXE, TDGXT), + DA_INST (0x64, RXY, LEY), + DA_INST (0x65, RXY, LDY), + DA_INST (0x66, RXY, STEY), + DA_INST (0x67, RXY, STDY), +}; + +static struct disassm_instruction l1[256] = { /* xx */ + DA_INST_TBL (0x01, l2_01, 8, 8), + DA_INST (0x04, RR, SPM), + DA_INST (0x05, RR, BALR), + DA_INST (0x06, RR, BCTR), + DA_INST (0x07, RR_MASK, BCR), + DA_INST (0x0A, I, SVC), + DA_INST (0x0B, RR, BSM), + DA_INST (0x0C, RR, BASSM), + DA_INST (0x0D, RR, BASR), + DA_INST (0x0E, RR, MVCL), + DA_INST (0x0F, RR, CLCL), + DA_INST (0x10, RR, LPR), + DA_INST (0x11, RR, LNR), + DA_INST (0x12, RR, LTR), + DA_INST (0x13, RR, LCR), + DA_INST (0x14, RR, NR), + DA_INST (0x15, RR, CLR), + DA_INST (0x16, RR, OR), + DA_INST (0x17, RR, XR), + DA_INST (0x18, RR, LR), + DA_INST (0x19, RR, CR), + DA_INST (0x1A, RR, AR), + DA_INST (0x1B, RR, SR), + DA_INST (0x1C, RR, MR), + DA_INST (0x1D, RR, DR), + DA_INST (0x1E, RR, ALR), + DA_INST (0x1F, RR, SLR), + DA_INST (0x20, RR, LPDR), + DA_INST (0x21, RR, LNDR), + DA_INST (0x22, RR, LTDR), + DA_INST (0x23, RR, LCDR), + DA_INST (0x24, RR, HDR), + DA_INST (0x25, RR, LDXR), + DA_INST (0x26, RR, MXR), + DA_INST (0x27, RR, MXDR), + DA_INST (0x28, RR, LDR), + DA_INST (0x29, RR, CDR), + DA_INST (0x2A, RR, ADR), + DA_INST (0x2B, RR, SDR), + DA_INST (0x2C, RR, MDR), + DA_INST (0x2D, RR, DDR), + DA_INST (0x2E, RR, AWR), + DA_INST (0x2F, RR, SWR), + DA_INST (0x30, RR, LPER), + DA_INST (0x31, RR, LNER), + DA_INST (0x32, RR, LTER), + DA_INST (0x33, RR, LCER), + DA_INST (0x34, RR, HER), + DA_INST (0x35, RR, LEDR), + DA_INST (0x36, RR, AXR), + DA_INST (0x37, RR, SXR), + DA_INST (0x38, RR, LER), + DA_INST (0x39, RR, CER), + DA_INST (0x3A, RR, AER), + DA_INST (0x3B, RR, SER), + DA_INST (0x3C, RR, MDER), + DA_INST (0x3D, RR, DER), + DA_INST (0x3E, RR, AUR), + DA_INST (0x3F, RR, SUR), + DA_INST (0x40, RX, STH), + DA_INST (0x41, RX, LA), + DA_INST (0x42, RX, STC), + DA_INST (0x43, RX, IC), + DA_INST (0x44, RX, EX), + DA_INST (0x45, RX, BAL), + DA_INST (0x46, RX, BCT), + DA_INST (0x47, RX_MASK, BC), + DA_INST (0x48, RX, LH), + DA_INST (0x49, RX, CH), + DA_INST (0x4A, RX, AH), + DA_INST (0x4B, RX, SH), + DA_INST (0x4C, RX, MH), + DA_INST (0x4D, RX, BAS), + DA_INST (0x4E, RX, CVD), + DA_INST (0x4F, RX, CVB), + DA_INST (0x50, RX, ST), + DA_INST (0x51, RX, LAE), + DA_INST (0x54, RX, N), + DA_INST (0x55, RX, CL), + DA_INST (0x56, RX, O), + DA_INST (0x57, RX, X), + DA_INST (0x58, RX, L), + DA_INST (0x59, RX, C), + DA_INST (0x5A, RX, A), + DA_INST (0x5B, RX, S), + DA_INST (0x5C, RX, M), + DA_INST (0x5D, RX, D), + DA_INST (0x5E, RX, AL), + DA_INST (0x5F, RX, SL), + DA_INST (0x60, RX, STD), + DA_INST (0x67, RX, MXD), + DA_INST (0x68, RX, LD), + DA_INST (0x69, RX, CD), + DA_INST (0x6A, RX, AD), + DA_INST (0x6B, RX, SD), + DA_INST (0x6C, RX, MD), + DA_INST (0x6D, RX, DD), + DA_INST (0x6E, RX, AW), + DA_INST (0x6F, RX, SW), + DA_INST (0x70, RX, STE), + DA_INST (0x71, RX, MS), + DA_INST (0x78, RX, LE), + DA_INST (0x79, RX, CE), + DA_INST (0x7A, RX, AE), + DA_INST (0x7B, RX, SE), + DA_INST (0x7C, RX, MDE), + DA_INST (0x7D, RX, DE), + DA_INST (0x7E, RX, AU), + DA_INST (0x7F, RX, SU), + DA_INST (0x80, S, SSM), + DA_INST (0x82, S, LPSW), + DA_INST (0x83, DIAG, DIAG), + DA_INST (0x84, RSI, BRXH), + DA_INST (0x85, RSI, BRXLE), + DA_INST (0x86, RS1, BXH), + DA_INST (0x87, RS1, BXLE), + DA_INST (0x88, RS1, SRL), + DA_INST (0x89, RS1, SLL), + DA_INST (0x8A, RS1, SRA), + DA_INST (0x8B, RS1, SLA), + DA_INST (0x8C, RS1, SRDL), + DA_INST (0x8D, RS1, SLDL), + DA_INST (0x8E, RS1, SRDA), + DA_INST (0x8F, RS1, SLDA), + DA_INST (0x90, RS1, STM), + DA_INST (0x91, SI, TM), + DA_INST (0x92, SI, MVI), + DA_INST (0x93, S, TS), + DA_INST (0x94, SI, NI), + DA_INST (0x95, SI, CLI), + DA_INST (0x96, SI, OI), + DA_INST (0x97, SI, XI), + DA_INST (0x98, RS1, LM), + DA_INST (0x99, RS1, TRACE), + DA_INST (0x9A, RS1, LAM), + DA_INST (0x9B, RS1, STAM), + DA_INST_TBL (0xA5, l2_a5, 4, 12), + DA_INST_TBL (0xA7, l2_a7, 4, 12), + DA_INST (0xA8, RS1, MVCLE), + DA_INST (0xA9, RS1, CLCLE), + DA_INST (0xAC, SI, STNSM), + DA_INST (0xAD, SI, STOSM), + DA_INST (0xAE, RS1, SIGP), + DA_INST (0xAF, SI, MC), + DA_INST (0xB1, RX, LRA), + DA_INST_TBL (0xB2, l2_b2, 8, 8), + DA_INST_TBL (0xB3, l2_b3, 8, 8), + DA_INST (0xB6, RS1, STCTL), + DA_INST (0xB7, RS1, LCTL), + DA_INST_TBL (0xB9, l2_b9, 8, 8), + DA_INST (0xBA, RS1, CS), + DA_INST (0xBB, RS1, CDS), + DA_INST (0xBD, RS2, CLM), + DA_INST (0xBE, RS2, STCM), + DA_INST (0xBF, RS2, ICM), + DA_INST_TBL (0xC0, l2_c0, 4, 12), + DA_INST_TBL (0xC2, l2_c2, 4, 12), + DA_INST_TBL (0xC4, l2_c4, 4, 12), + DA_INST_TBL (0xC6, l2_c6, 4, 12), + DA_INST_TBL (0xC8, l2_c8, 4, 12), + DA_INST (0xD0, SS1, TRTR), + DA_INST (0xD1, SS1, MVN), + DA_INST (0xD2, SS1, MVC), + DA_INST (0xD3, SS1, MVZ), + DA_INST (0xD4, SS1, NC), + DA_INST (0xD5, SS1, CLC), + DA_INST (0xD6, SS1, OC), + DA_INST (0xD7, SS1, XC), + DA_INST (0xD9, SS4, MVCK), + DA_INST (0xDA, SS4, MVCP), + DA_INST (0xDB, SS4, MVCS), + DA_INST (0xDC, SS1, TR), + DA_INST (0xDD, SS1, TRT), + DA_INST (0xDE, SS1, ED), + DA_INST (0xDF, SS1, EDMK), + DA_INST (0xE1, SS1, PKU), + DA_INST (0xE2, SS1, UNPKU), + DA_INST_TBL (0xE3, l2_e3, 8, 40), + DA_INST_TBL (0xE5, l2_e5, 8, 8), + DA_INST (0xE8, SS1, MVCIN), + DA_INST (0xE9, SS1, PKA), + DA_INST (0xEA, SS1, UNPKA), + DA_INST_TBL (0xEB, l2_eb, 8, 40), + DA_INST_TBL (0xEC, l2_ec, 8, 40), + DA_INST_TBL (0xED, l2_ed, 8, 40), + DA_INST (0xEE, SS5, PLO), + DA_INST (0xEF, SS5, LMD), + DA_INST (0xF0, SS3, SRP), + DA_INST (0xF1, SS2, MVO), + DA_INST (0xF2, SS2, PACK), + DA_INST (0xF3, SS2, UNPK), + DA_INST (0xF8, SS2, ZAP), + DA_INST (0xF9, SS2, CP), + DA_INST (0xFA, SS2, AP), + DA_INST (0xFB, SS2, SP), + DA_INST (0xFC, SS2, MP), + DA_INST (0xFD, SS2, DP), +}; + +static int da_snprintf(u8 *bytes, char *buf, int buflen, u8 opcode, struct + disassm_instruction *table) +{ +#define IPFX "%-6s " + + int ilc = opcode >> 6; + struct disassm_instruction *inst = &table[opcode]; + + switch (inst->fmt) { + case IF_INV: + snprintf(buf, buflen, "??"); + break; + case IF_VAR: + { + unsigned char subop; /* sub op-code */ + + /* get the right byte */ + subop = *(bytes+(inst->loc/8)); + + /* shift the needed portion right */ + subop >>= 8 - inst->len - (inst->loc%8); + + /* mask out any unneeded high bits */ + subop &= (1 << inst->len) - 1; + + snprintf(buf, buflen, "??? (many, X'%02X'+ " + "X'%02X', table = %p)", opcode, subop, + inst->u.ptr); + if (inst->u.ptr) + da_snprintf(bytes, buf, buflen, subop, inst->u.ptr); + break; + } + case IF_DIAG: + snprintf(buf, buflen, IPFX "X'%06X'", + inst->u.name, + *((u32*)(bytes)) & 0xffffff); /* I */ + break; + case IF_E: + snprintf(buf, buflen, IPFX, + inst->u.name); + break; + case IF_I: + snprintf(buf, buflen, IPFX "X'%02X'", + inst->u.name, + *(bytes+1)); /* I */ + break; + case IF_RI1: + case IF_RI2: + snprintf(buf, buflen, IPFX "%s%d,%d", + inst->u.name, + (inst->fmt == IF_RI1 ? "R" : ""), /* reg/mask */ + bytes[1] >> 4, /* R1/M1 */ + *((u16*)(bytes+2))); /* I2 */ + break; + case IF_RIL1: + case IF_RIL2: + snprintf(buf, buflen, IPFX "%s%d,%d", + inst->u.name, + (inst->fmt == IF_RIL1 ? "R" : ""), /* reg/mask */ + bytes[1] >> 4, /* R1/M1 */ + *((u32*)(bytes+2))); /* I2 */ + break; + case IF_RR: + case IF_RR_MASK: + snprintf(buf, buflen, IPFX "%s%d,R%d", + inst->u.name, + inst->fmt == IF_RR_MASK ? "" : "R", + bytes[1] >> 4, /* R1 */ + bytes[1] & 0xf); /* R2 */ + break; + case IF_RRE: + snprintf(buf, buflen, IPFX "R%d,R%d", + inst->u.name, + bytes[3] >> 4, /* R1 */ + bytes[3] & 0xf); /* R2 */ + break; + case IF_RS1: + case IF_RS2: + snprintf(buf, buflen, IPFX "R%d,%s%d,%d(R%d)", + inst->u.name, + bytes[1] >> 4, /* R1 */ + (inst->fmt == IF_RS1 ? "R" : ""), /* reg/mask */ + bytes[1] & 0xf, /* R3/M3 */ + *((u16*)(bytes+2)) & 0x0fff, /* D2 */ + bytes[2] >> 4); /* B2 */ + break; + case IF_RSI: + snprintf(buf, buflen, IPFX "R%d,R%d,%d", + inst->u.name, + bytes[1] >> 4, /* R1 */ + bytes[1] & 0xf, /* R3 */ + *((u16*)(bytes+2))); /* I2 */ + break; + case IF_RSY1: + case IF_RSY2: + snprintf(buf, buflen, IPFX "R%d,%s%d,%d(R%d)", + inst->u.name, + bytes[1] >> 4, /* R1 */ + (inst->fmt == IF_RSY1 ? "R" : ""), /* reg/mask */ + bytes[1] & 0xf, /* R3/M3 */ + ((u32)*((u16*)(bytes+2)) & 0x0fff) + + (((u32)*(bytes+4)) << 12), /* D2 */ + bytes[2] >> 4); /* B2 */ + break; + case IF_RX: + case IF_RX_MASK: + snprintf(buf, buflen, IPFX "%s%d,%d(R%d,R%d)", + inst->u.name, + inst->fmt == IF_RX_MASK ? "" : "R", + bytes[1] >> 4, /* R1 */ + *((u16*)(bytes+2)) & 0x0fff, /* D2 */ + bytes[1] & 0xf, /* X2 */ + bytes[2] >> 4); /* B2 */ + break; + case IF_RXY: + snprintf(buf, buflen, IPFX "R%d,%d(R%d,R%d)", + inst->u.name, + bytes[1] >> 4, /* R1 */ + ((u32)*((u16*)(bytes+2)) & 0x0fff) + + (((u32)*(bytes+4)) << 12), /* D2 */ + bytes[1] & 0xf, /* X2 */ + bytes[2] >> 4); /* B2 */ + break; + case IF_S: + snprintf(buf, buflen, IPFX "%d(R%d)", + inst->u.name, + *((u16*)(bytes+2)) & 0x0fff, /* D2 */ + bytes[2] >> 4); /* B2 */ + break; + case IF_SI: + snprintf(buf, buflen, IPFX "%d(R%d),%d", + inst->u.name, + *((u16*)(bytes+2)) & 0x0fff, /* D1 */ + bytes[2] >> 4, /* B1 */ + bytes[1]); /* I2 */ + break; + case IF_SS1: + snprintf(buf, buflen, IPFX "%d(%d,R%d),%d(R%d)", + inst->u.name, + *((u16*)(bytes+2)) & 0x0fff, /* D1 */ + bytes[1]+1, /* L */ + bytes[2] >> 4, /* B1 */ + *((u16*)(bytes+4)) & 0x0fff, /* D2 */ + bytes[4] >> 4); /* B2 */ + break; + case IF_SS2: + snprintf(buf, buflen, IPFX "%d(%d,R%d),%d(%d,R%d)", + inst->u.name, + *((u16*)(bytes+2)) & 0x0fff, /* D1 */ + (bytes[1] >> 4) + 1, /* L1 */ + bytes[2] >> 4, /* B1 */ + *((u16*)(bytes+4)) & 0x0fff, /* D2 */ + (bytes[1] & 0xf) + 1, /* L2 */ + bytes[4] >> 4); /* B2 */ + break; + case IF_SS3: + snprintf(buf, buflen, IPFX "%d(%d,R%d),%d(R%d),%d", + inst->u.name, + *((u16*)(bytes+2)) & 0x0fff, /* D1 */ + (bytes[1] >> 4) + 1, /* L1 */ + bytes[2] >> 4, /* B1 */ + *((u16*)(bytes+4)) & 0x0fff, /* D2 */ + bytes[4] >> 4, /* B2 */ + bytes[1] & 0xf); /* I3 */ + break; + case IF_SS4: + snprintf(buf, buflen, IPFX "%d(%d,R%d),%d(R%d),R%d", + inst->u.name, + *((u16*)(bytes+2)) & 0x0fff, /* D1 */ + (bytes[1] >> 4) + 1, /* L1 */ + bytes[2] >> 4, /* B1 */ + *((u16*)(bytes+4)) & 0x0fff, /* D2 */ + bytes[4] >> 4, /* B2 */ + bytes[1] & 0xf); /* R3 */ + break; + case IF_SS5: + snprintf(buf, buflen, IPFX "R%d,R%d,%d(R%d),%d(R%d)", + inst->u.name, + bytes[1] >> 4, /* R1 */ + bytes[1] & 0xf, /* R3 */ + *((u16*)(bytes+2)) & 0x0fff, /* D2 */ + bytes[2] >> 4, /* B2 */ + *((u16*)(bytes+4)) & 0x0fff, /* D4 */ + bytes[4] >> 4); /* B4 */ + break; + default: + snprintf(buf, buflen, "%s ???", inst->u.name); + break; + } + + /* return instruction length in bytes */ + return 2 * (ilc >= 2 ? ilc : ilc + 1); +} + +int disassm(u8 *bytes, char *buf, int buflen) +{ + return da_snprintf(bytes, buf, buflen, *bytes, l1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/exception.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,16 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <sched.h> +#include <vcpu.h> + +void queue_prog_exception(struct virt_sys *sys, enum PROG_EXCEPTION type, u64 param) +{ + con_printf(sys->con, "FIXME: supposed to inject a %d program exception\n", type); + sys->task->cpu->state = GUEST_STOPPED; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/guest.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,65 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <directory.h> +#include <sched.h> +#include <dat.h> +#include <shell.h> + +/* + * FIXME: + * - issue any pending interruptions + */ +void run_guest(struct virt_sys *sys) +{ + u64 save_gpr[16]; + + /* + * FIXME: need to ->icptcode = 0; + */ + + /* + * FIXME: load FPRs & FPCR + */ + + /* + * IMPORTANT: We MUST keep a valid stack address in R15. This way, + * if SIE gets interrupted via an interrupt in the host, the + * scheduler can still get to the struct task pointer on the stack + */ + asm volatile( + /* save current regs */ + " stmg 0,15,%0\n" + /* load the address of the guest state save area */ + " lr 14,%1\n" + /* load the address of the reg save area */ + " la 15,%0\n" + /* load guest's R0-R13 */ + " lmg 0,13,%2(14)\n" + /* SIE */ + " sie %3(14)\n" + /* save guest's R0-R13 */ + " stmg 0,13,%2(14)\n" + /* restore all regs */ + " lmg 0,15,0(15)\n" + + : /* output */ + "+m" (save_gpr) + : /* input */ + "a" (sys->task->cpu), + "J" (offsetof(struct virt_cpu, regs.gpr)), + "J" (offsetof(struct virt_cpu, sie_cb)) + : /* clobbered */ + "memory" + ); + + /* + * FIXME: store FPRs & FPCR + */ + + handle_interception(sys); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/guest_ipl.S Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,121 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + + # + # We are guaranteed the following: + # + # 1) we are located above 16M + # 2) we are located below 2G + # 3) we are running in ESA/390 + # 4) we are in 31-bit addressing mode + # 5) the guest registers are saved at GUEST_IPL_REGSAVE + # 6) R1 contains the subchannel # + # 7) R2 contains the device # + # 8) R12 contains the base address + # + # Register usage: + # + # R1 = subchannel number + # R2 = device number + # R3 = temp + # R12 = base for this code + # + + # Nice register names +.equ r0,0 +.equ r1,1 +.equ r2,2 +.equ r3,3 +.equ r12,12 +.equ r15,15 + + # new IO interruption PSW address +.equ PSANEWIO,120 + +############################################################################### +# Code begins here # +############################################################################### + +.globl GUEST_IPL_CODE + .type GUEST_IPL_CODE, @function +GUEST_IPL_CODE: + STSCH SCHIB(r12) # get the SCHIB + BNZ ERROR(r12) + + OI SCHIB+5(r12),0x80 # enable the subchannel + + MSCH SCHIB(r12) # load up the SCHIB + BNZ ERROR(r12) + + # got a functioning subchannel, let's set up the new IO psw + + MVC PSANEWIO(8,r0),IOPSW(r12) + + L r3,PSANEWIO+4(r0,r0) + LA r3,IO(r3,r12) # calculate the address of + ST r3,PSANEWIO+4(r0,r0) # the IO handler + + # let's set up a CCW + an ORB, start the IO, and wait + + MVC 0(8,r0),INITCCW(r12) # set up the initial CCW + OI ORB+6(r12),0xff # set the LPM in the ORB + + SSCH ORB(r12) # start the IO + BNZ ERROR(r12) + + LPSW ENABLEDWAIT(r12) # wait for IO interruptions + +.equ IO,(.-GUEST_IPL_CODE) + # this is the IO interrupt handler + + B DONE(r12) + +.equ ERROR,(.-GUEST_IPL_CODE) + # an error occured, return an error + + LM r0,r15,REGSAVE(r12) + DIAG r0,r0,1 # return to hypervisor + +.equ DONE,(.-GUEST_IPL_CODE) + # we were successful! + + LM r0,r15,REGSAVE(r12) + DIAG r0,r0,0 # return to hypervisor + +############################################################################### +# Data begins here # +############################################################################### + +.equ DISABLEDWAIT,(.-GUEST_IPL_CODE) + .long 0x000c0000 + .long 0x80000000 # disabled wait PSW; signal + # return to hypervisor +.equ ENABLEDWAIT,(.-GUEST_IPL_CODE) + .long 0x020c0000 + .long 0x80000000 # enabled wait PSW; wait for IO + +.equ IOPSW,(.-GUEST_IPL_CODE) + .long 0x00080000 + .long 0x80000000 # new IO psw + +.equ INITCCW,(.-GUEST_IPL_CODE) + .long 0x02000000 + .long 0x60000018 # fmt0, read 24 bytes to addr 0 + + .align 4 +.equ ORB,(.-GUEST_IPL_CODE) + .skip (8*4),0 # the ORB is BIG + + .align 4 +.equ SCHIB,(.-GUEST_IPL_CODE) + .skip (13*4),0 # the SCHIB is BIG + + .align 4 +.globl GUEST_IPL_REGSAVE + .type GUEST_IPL_REGSAVE, @function +GUEST_IPL_REGSAVE: +.equ REGSAVE,(.-GUEST_IPL_CODE) # register save area
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/init.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,327 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <directory.h> +#include <sched.h> +#include <errno.h> +#include <page.h> +#include <buddy.h> +#include <slab.h> +#include <dat.h> +#include <clock.h> +#include <ebcdic.h> +#include <vdevice.h> +#include <cpu.h> +#include <mutex.h> +#include <vsprintf.h> +#include <shell.h> + +/* This is used to con_printf to the operator about various async events - + * e.g., user logon + */ +struct console *oper_con; + +static LIST_HEAD(online_users); +static UNLOCKED_MUTEX(online_users_lock); + +static int __alloc_guest_devices(struct virt_sys *sys) +{ + int i; + + INIT_LIST_HEAD(&sys->virt_devs); + + for(i=0; sys->directory->devices[i].type != VDEV_INVAL; i++) { + if (alloc_virt_dev(sys, &sys->directory->devices[i], + 0x10000 + i)) + con_printf(sys->con, "Failed to allocate vdev %04X, SCH = %05X\n", + sys->directory->devices[i].vdev, + 0x10000 + i); + } + + return 0; +} + +static int __alloc_guest_storage(struct virt_sys *sys) +{ + u64 pages = sys->directory->storage_size >> PAGE_SHIFT; + struct page *p; + + INIT_LIST_HEAD(&sys->guest_pages); + + while (pages) { + p = alloc_pages(0, ZONE_NORMAL); + if (!p) + continue; /* FIXME: sleep? */ + + list_add(&p->guest, &sys->guest_pages); + + pages--; + + dat_insert_page(&sys->as, (u64) page_to_addr(p), + pages << PAGE_SHIFT); + } + + return 0; +} + +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\n", ret); + break; + } +} + +static int shell_init(void *data) +{ + struct virt_sys *sys = data; + struct virt_cpu *cpu; + struct datetime dt; + struct page *page; + + page = alloc_pages(0, ZONE_NORMAL); + BUG_ON(!page); + + cpu = page_to_addr(page); + sys->task->cpu = cpu; + + memset(cpu, 0, PAGE_SIZE); + + __alloc_guest_storage(sys); + __alloc_guest_devices(sys); + + /* + * load guest's address space into the host's PASCE + */ + load_as(&sys->as); + + cpu->cpuid = getcpuid() | 0xFF00000000000000ULL; + + memset(&cpu->sie_cb, 0, sizeof(struct sie_cb)); + cpu->sie_cb.gmsor = 0; + cpu->sie_cb.gmslm = sys->directory->storage_size; + cpu->sie_cb.gbea = 1; + cpu->sie_cb.ecb = 2; + cpu->sie_cb.eca = 0xC1002001U; + /* + * TODO: What about ->scaoh and ->scaol? + */ + + 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(); + } + + 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; + + 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("operator"); + BUG_ON(IS_ERR(sys->directory)); + + sys->print_ts = 1; /* print timestamps */ + + sys->task = create_task("OPERATOR-vcpu0", 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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/instruction.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,30 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <sched.h> +#include <shell.h> + +static const intercept_handler_t instruction_funcs[256] = { + [0xb2] = handle_instruction_priv, /* assorted priv. insts */ +}; + +int handle_instruction(struct virt_sys *sys) +{ + struct virt_cpu *cpu = sys->task->cpu; + intercept_handler_t h; + int err = -EINVAL; + + con_printf(sys->con, "INTRCPT: INST (%04x %08x)\n", + cpu->sie_cb.ipa, + cpu->sie_cb.ipb); + + h = instruction_funcs[cpu->sie_cb.ipa >> 8]; + if (h) + err = h(sys); + + return err; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/instruction_priv.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,224 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <list.h> +#include <sched.h> +#include <vdevice.h> +#include <vcpu.h> +#include <shell.h> + +static int handle_msch(struct virt_sys *sys) +{ + struct virt_cpu *cpu = sys->task->cpu; + + u64 r1 = __guest_gpr(cpu, 1); + u64 addr = RAW_S_1(cpu); + + struct schib *gschib; + struct virt_device *vdev, *vdev_cur; + int ret = 0; + + if ((PAGE_SIZE-(addr & PAGE_MASK)) < sizeof(struct schib)) { + con_printf(sys->con, "The SCHIB crosses page boundary (%016llx; %lu)! CPU stopped\n", + addr, sizeof(struct schib)); + cpu->state = GUEST_STOPPED; + goto out; + } + + /* sch number must be: X'0001____' */ + if ((r1 & 0xffff0000) != 0x00010000) { + queue_prog_exception(sys, PROG_OPERAND, r1); + goto out; + } + + /* schib must be word-aligned */ + if (addr & 0x3) { + queue_prog_exception(sys, PROG_SPEC, addr); + goto out; + } + + /* find the virtual device */ + vdev = NULL; + list_for_each_entry(vdev_cur, &sys->virt_devs, devices) { + if (vdev_cur->sch == (u32) r1) { + vdev = vdev_cur; + break; + } + } + + /* There's no virtual device with this sch number; CC=3 */ + if (!vdev) { + cpu->sie_cb.gpsw.cc = 3; + goto out; + } + + /* translate guest address to host address */ + ret = virt2phy_current(addr, &addr); + if (ret) { + if (ret != -EFAULT) + goto out; + + ret = 0; + queue_prog_exception(sys, PROG_ADDR, addr); + goto out; + } + + gschib = (struct schib*) addr; + + /* + * Condition code 1 is set, and no other action is taken, when the + * subchannel is status pending. (See “Status Control (SC)” on + * page 16-16.) + */ + if (vdev->scsw.sc & SC_STATUS) { + cpu->sie_cb.gpsw.cc = 1; + goto out; + } + + /* + * Condition code 2 is set, and no other action is taken, when a + * clear, halt, or start function is in progress at the + * subchannel. (See “Function Control (FC)” on page 16-12.) + */ + if (vdev->scsw.fc & (FC_START | FC_HALT | FC_CLEAR)) { + cpu->sie_cb.gpsw.cc = 2; + goto out; + } + + /* + * The channel-subsystem operations that may be influenced due to + * placement of SCHIB information in the subchannel are: + * + * • I/O processing (E field) + * • Interruption processing (interruption parameter and ISC field) + * • Path management (D, LPM, and POM fields) + * • Monitoring and address-limit checking (measurement-block index, + * LM, and MM fields) + * • Measurement-block-format control (F field) + * • Extended-measurement-word-mode enable (X field) + * • Concurrent-sense facility (S field) + * • Measurement-block address (MBA) + */ + + if (!gschib->pmcw.v) + goto out_cc0; + + vdev->pmcw.interrupt_param = gschib->pmcw.interrupt_param; + vdev->pmcw.e = gschib->pmcw.e; + vdev->pmcw.isc = gschib->pmcw.isc; + vdev->pmcw.d = gschib->pmcw.d; + vdev->pmcw.lpm = gschib->pmcw.lpm; + vdev->pmcw.pom = gschib->pmcw.pom; + vdev->pmcw.lm = gschib->pmcw.lm; + vdev->pmcw.mm = gschib->pmcw.mm; + vdev->pmcw.f = gschib->pmcw.f; + vdev->pmcw.x = gschib->pmcw.x; + vdev->pmcw.s = gschib->pmcw.s; + vdev->pmcw.mbi = gschib->pmcw.mbi; + /* FIXME: save measurement-block address */ + +out_cc0: + cpu->sie_cb.gpsw.cc = 0; + +out: + return ret; +} + +static int handle_ssch(struct virt_sys *sys) +{ + con_printf(sys->con, "SSCH handler\n"); + return -ENOMEM; +} + +static int handle_stsch(struct virt_sys *sys) +{ + struct virt_cpu *cpu = sys->task->cpu; + + u64 r1 = __guest_gpr(cpu, 1); + u64 addr = RAW_S_1(cpu); + + struct schib *gschib; + struct virt_device *vdev, *vdev_cur; + int ret = 0; + + if ((PAGE_SIZE-(addr & PAGE_MASK)) < sizeof(struct schib)) { + con_printf(sys->con, "The SCHIB crosses page boundary (%016llx; %lu)! CPU stopped\n", + addr, sizeof(struct schib)); + cpu->state = GUEST_STOPPED; + goto out; + } + + /* sch number must be: X'0001____' */ + if ((r1 & 0xffff0000) != 0x00010000) { + queue_prog_exception(sys, PROG_OPERAND, r1); + goto out; + } + + /* schib must be word-aligned */ + if (addr & 0x3) { + queue_prog_exception(sys, PROG_SPEC, addr); + goto out; + } + + /* find the virtual device */ + vdev = NULL; + list_for_each_entry(vdev_cur, &sys->virt_devs, devices) { + if (vdev_cur->sch == (u32) r1) { + vdev = vdev_cur; + break; + } + } + + /* There's no virtual device with this sch number; CC=3 */ + if (!vdev) { + cpu->sie_cb.gpsw.cc = 3; + goto out; + } + + /* translate guest address to host address */ + ret = virt2phy_current(addr, &addr); + if (ret) { + if (ret == -EFAULT) { + ret = 0; + queue_prog_exception(sys, PROG_ADDR, addr); + } + + goto out; + } + + gschib = (struct schib*) addr; + + /* copy! */ + memcpy(&gschib->pmcw, &vdev->pmcw, sizeof(struct pmcw)); + memcpy(&gschib->scsw, &vdev->scsw, sizeof(struct scsw)); + + /* CC: 0 */ + cpu->sie_cb.gpsw.cc = 0; + +out: + return ret; +} + +static const intercept_handler_t instruction_priv_funcs[256] = { + [0x32] = handle_msch, + [0x33] = handle_ssch, + [0x34] = handle_stsch, +}; + +int handle_instruction_priv(struct virt_sys *sys) +{ + struct virt_cpu *cpu = sys->task->cpu; + intercept_handler_t h; + int err = -EINVAL; + + h = instruction_priv_funcs[cpu->sie_cb.ipa & 0xff]; + if (h) + err = h(sys); + + return err; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/intercept.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,125 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <directory.h> +#include <sched.h> +#include <dat.h> +#include <shell.h> + +static int handle_noop(struct virt_sys *sys) +{ + return 0; +} + +static int handle_program(struct virt_sys *sys) +{ + con_printf(sys->con, "INTRCPT: PROG\n"); + sys->task->cpu->state = GUEST_STOPPED; + return 0; +} + +static int handle_instruction_and_program(struct virt_sys *sys) +{ + con_printf(sys->con, "INTRCPT: INST+PROG\n"); + sys->task->cpu->state = GUEST_STOPPED; + return 0; +} + +static int handle_ext_req(struct virt_sys *sys) +{ + con_printf(sys->con, "INTRCPT: EXT REQ\n"); + sys->task->cpu->state = GUEST_STOPPED; + return 0; +} + +static int handle_ext_int(struct virt_sys *sys) +{ + con_printf(sys->con, "INTRCPT: EXT INT\n"); + sys->task->cpu->state = GUEST_STOPPED; + return 0; +} + +static int handle_io_req(struct virt_sys *sys) +{ + con_printf(sys->con, "INTRCPT: IO REQ\n"); + sys->task->cpu->state = GUEST_STOPPED; + return 0; +} + +static int handle_wait(struct virt_sys *sys) +{ + con_printf(sys->con, "INTRCPT: WAIT\n"); + sys->task->cpu->state = GUEST_STOPPED; + return 0; +} + +static int handle_validity(struct virt_sys *sys) +{ + con_printf(sys->con, "INTRCPT: VALIDITY\n"); + sys->task->cpu->state = GUEST_STOPPED; + return 0; +} + +static int handle_stop(struct virt_sys *sys) +{ + atomic_clear_mask(CPUSTAT_STOP_INT, &sys->task->cpu->sie_cb.cpuflags); + return 0; +} + +static int handle_oper_except(struct virt_sys *sys) +{ + con_printf(sys->con, "INTRCPT: OPER EXCEPT\n"); + sys->task->cpu->state = GUEST_STOPPED; + return 0; +} + +static int handle_exp_run(struct virt_sys *sys) +{ + con_printf(sys->con, "INTRCPT: EXP RUN\n"); + sys->task->cpu->state = GUEST_STOPPED; + return 0; +} + +static int handle_exp_timer(struct virt_sys *sys) +{ + con_printf(sys->con, "INTRCPT: EXP TIMER\n"); + sys->task->cpu->state = GUEST_STOPPED; + return 0; +} + +static const intercept_handler_t intercept_funcs[0x4c >> 2] = { + [0x00 >> 2] = handle_noop, + [0x04 >> 2] = handle_instruction, + [0x08 >> 2] = handle_program, + [0x0c >> 2] = handle_instruction_and_program, + [0x10 >> 2] = handle_ext_req, + [0x14 >> 2] = handle_ext_int, + [0x18 >> 2] = handle_io_req, + [0x1c >> 2] = handle_wait, + [0x20 >> 2] = handle_validity, + [0x28 >> 2] = handle_stop, + [0x2c >> 2] = handle_oper_except, + [0x44 >> 2] = handle_exp_run, + [0x48 >> 2] = handle_exp_timer, +}; + +void handle_interception(struct virt_sys *sys) +{ + struct virt_cpu *cpu = sys->task->cpu; + intercept_handler_t h; + int err = -EINVAL; + + h = intercept_funcs[cpu->sie_cb.icptcode >> 2]; + if (h) + err = h(sys); + + if (err) { + cpu->state = GUEST_STOPPED; + con_printf(sys->con, "Unknown/mis-handled intercept code %02x, err = %d\n", + cpu->sie_cb.icptcode, err); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/reset.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,225 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <directory.h> +#include <sched.h> +#include <dat.h> +#include <shell.h> + +#define RESET_CPU 0x000001 +#define SET_ESA390 0x000002 +#define RESET_PSW 0x000004 +#define RESET_PREFIX 0x000008 +#define RESET_CPU_TIMER 0x000010 +#define RESET_CLK_COMP 0x000020 +#define RESET_TOD_PROG_REG 0x000040 +#define RESET_CR 0x000080 +#define RESET_BREAK_EV_ADDR 0x000100 +#define RESET_FPCR 0x000200 +#define RESET_AR 0x000400 +#define RESET_GPR 0x000800 +#define RESET_FPR 0x001000 +#define RESET_STORAGE_KEYS 0x002000 +#define RESET_STORAGE 0x004000 +#define RESET_NONVOL_STORAGE 0x008000 +#define RESET_EXPANDED_STORAGE 0x010000 +#define RESET_TOD 0x020000 +#define RESET_TOD_STEER 0x040000 +#define RESET_FLOATING_INTERRUPTIONS 0x080000 +#define RESET_IO 0x100000 +#define RESET_PLO_LOCKS 0x200000 +#define __RESET_PLO_LOCKS_PRESERVE 0x400000 +#define RESET_PLO_LOCKS_PRESERVE (RESET_PLO_LOCKS | \ + __RESET_PLO_LOCKS_PRESERVE) + +/* + * These define all the different ways of reseting the system...to save us + * typing later on :) + */ +#define SUBSYSTEM_RESET_FLAGS (RESET_FLOATING_INTERRUPTIONS | RESET_IO) +#define CPU_RESET_FLAGS (RESET_CPU) +#define INIT_CPU_RESET_FLAGS (RESET_CPU | SET_ESA390 | RESET_PSW | \ + RESET_PREFIX | RESET_CPU_TIMER | \ + RESET_CLK_COMP | RESET_TOD_PROG_REG | \ + RESET_CR | RESET_BREAK_EV_ADDR | \ + RESET_FPCR) +#define CLEAR_RESET_FLAGS (RESET_CPU | SET_ESA390 | RESET_PSW | \ + RESET_PREFIX | RESET_CPU_TIMER | \ + RESET_CLK_COMP | RESET_TOD_PROG_REG | \ + RESET_CR | RESET_BREAK_EV_ADDR | RESET_FPCR | \ + RESET_AR | RESET_GPR | RESET_FPR | \ + RESET_STORAGE_KEYS | RESET_STORAGE | \ + RESET_NONVOL_STORAGE | RESET_PLO_LOCKS | \ + RESET_FLOATING_INTERRUPTIONS | RESET_IO) +#define POWER_ON_RESET_FLAGS (RESET_CPU | SET_ESA390 | RESET_PSW | \ + RESET_PREFIX | RESET_CPU_TIMER | \ + RESET_CLK_COMP | RESET_TOD_PROG_REG | \ + RESET_CR | RESET_BREAK_EV_ADDR | RESET_FPCR | \ + RESET_AR | RESET_GPR | RESET_FPR | \ + RESET_STORAGE_KEYS | RESET_STORAGE | \ + RESET_EXPANDED_STORAGE | RESET_TOD | \ + RESET_TOD_STEER | RESET_PLO_LOCKS_PRESERVE | \ + RESET_FLOATING_INTERRUPTIONS | RESET_IO) + +/* + * Reset TODO: + * - handle Captured-z/Architecture-PSW register + */ +static void __perform_cpu_reset(struct virt_sys *sys, int flags) +{ + struct virt_cpu *cpu = sys->task->cpu; + + if (flags & RESET_CPU) { + if (flags & SET_ESA390) { + /* FIXME: set the arch mode to ESA/390 */ + } + + /* + * FIXME: clear interruptions: + * - PROG + * - SVC + * - local EXT (floating EXT are NOT cleared) + * - MCHECK (floating are NOT cleared) + */ + + cpu->state = GUEST_STOPPED; + } + + if (flags & RESET_PSW) + memset(&cpu->sie_cb.gpsw, 0, sizeof(struct psw)); + + if (flags & RESET_PREFIX) + cpu->sie_cb.prefix = 0; + + if (flags & RESET_CPU_TIMER) { + /* FIXME */ + } + + if (flags & RESET_CLK_COMP) { + /* FIXME */ + } + + if (flags & RESET_TOD_PROG_REG) { + /* FIXME */ + } + + if (flags & RESET_CR) { + memset(cpu->sie_cb.gcr, 0, 16*sizeof(u64)); + cpu->sie_cb.gcr[0] = 0xE0UL; + cpu->sie_cb.gcr[14] = 0xC2000000UL; + } + + if (flags & RESET_BREAK_EV_ADDR) { + /* FIXME: initialize to 0x1 */ + } + + if (flags & RESET_FPCR) + cpu->regs.fpcr = 0; + + if (flags & RESET_AR) + memset(cpu->regs.ar, 0, 16*sizeof(u32)); + + if (flags & RESET_GPR) + memset(cpu->regs.gpr, 0, 16*sizeof(u64)); + + if (flags & RESET_FPR) + memset(cpu->regs.fpr, 0, 16*sizeof(u64)); + + if (flags & RESET_STORAGE_KEYS) { + } + + if (flags & RESET_STORAGE) { + struct page *p; + + list_for_each_entry(p, &sys->guest_pages, guest) + memset(page_to_addr(p), 0, PAGE_SIZE); + } + + if (flags & RESET_NONVOL_STORAGE) { + } + + if (flags & RESET_EXPANDED_STORAGE) { + } + + if (flags & RESET_TOD) { + } + + if (flags & RESET_TOD_STEER) { + } + + if (flags & RESET_PLO_LOCKS) { + /* + * TODO: if RESET_PLO_LOCKS_PRESERVE is set, don't reset + * locks held by powered on CPUS + */ + } +} + +static void __perform_noncpu_reset(struct virt_sys *sys, int flags) +{ + if (flags & RESET_FLOATING_INTERRUPTIONS) { + } + + if (flags & RESET_IO) { + } +} + +/**************/ + +void guest_power_on_reset(struct virt_sys *sys) +{ + __perform_cpu_reset(sys, POWER_ON_RESET_FLAGS); + __perform_noncpu_reset(sys, POWER_ON_RESET_FLAGS); +} + +void guest_system_reset_normal(struct virt_sys *sys) +{ + __perform_cpu_reset(sys, CPU_RESET_FLAGS); + + /* + * TODO: once we have SMP guests, all other cpus should get a + * CPU_RESET_FLAGS as well. + */ + + __perform_noncpu_reset(sys, SUBSYSTEM_RESET_FLAGS); +} + +void guest_system_reset_clear(struct virt_sys *sys) +{ + __perform_cpu_reset(sys, CLEAR_RESET_FLAGS); + + /* + * TODO: once we have SMP guests, all other cpus should get a + * CLEAR_RESET_FLAGS as well. + */ + + __perform_noncpu_reset(sys, CLEAR_RESET_FLAGS); +} + +void guest_load_normal(struct virt_sys *sys) +{ + __perform_cpu_reset(sys, INIT_CPU_RESET_FLAGS); + + /* + * TODO: once we have SMP guests, all other cpus should get a + * CPU_RESET_FLAGS. + */ + + __perform_noncpu_reset(sys, SUBSYSTEM_RESET_FLAGS); +} + +void guest_load_clear(struct virt_sys *sys) +{ + __perform_cpu_reset(sys, CLEAR_RESET_FLAGS); + + /* + * TODO: once we have SMP guests, all other cpus should get a + * CLEAR_RESET_FLAGS as well. + */ + + __perform_noncpu_reset(sys, CLEAR_RESET_FLAGS); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cp/shell/splash.c Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,25 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include <splash.h> + +char *splash[] = { + " HH HH VV VV FFFFFFFFFFFF\n", + " HH HH VV VV FFFFFFFFFFFF\n", + " HH HH VV VV FF\n", + " HH HH VV VV FF\n", + " HH HH VV VV FF\n", + " HHHHHHHHHHHH VV VV FFFFFFF\n", + " HHHHHHHHHHHH VV VV FFFFFFF\n", + " HH HH VV VV FF\n", + " HH HH VV VV FF\n", + " HH HH VV VV FF\n", + " HH HH VVVV FF\n", + " HH HH VV FF\n", + "\n", + NULL, +};
--- a/doc/manual/cp-directory.tex Tue Dec 29 20:04:16 2009 -0500 +++ b/doc/manual/cp-directory.tex Fri Jun 18 20:41:48 2010 -0400 @@ -94,7 +94,7 @@ \begin{figure*}[htb] \small -\lstinputlisting{../../sys/hvf.directory} +\lstinputlisting{../../cp/hvf.directory} \captionfont \caption{\capfont Example directory defining three users.} \label{fig:directory-sample}
--- a/doc/manual/gen-docs.sh Tue Dec 29 20:04:16 2009 -0500 +++ b/doc/manual/gen-docs.sh Fri Jun 18 20:41:48 2010 -0400 @@ -115,7 +115,7 @@ rm -f cp-cmd-list.tex mkdir -p tex/ -for srcf in ../../sys/cp/cmd_*.c ; do +for srcf in ../../cp/shell/cmd_*.c ; do echo "Inspecting $srcf..." write_docs $srcf tex #write_docs $srcf txt
--- a/hercules/hvf.cnf Tue Dec 29 20:04:16 2009 -0500 +++ b/hercules/hvf.cnf Fri Jun 18 20:41:48 2010 -0400 @@ -31,7 +31,7 @@ #--- ---- -------------------- # Card Reader -000C 3505 ../sys/loader_rdr.bin ../sys/hvf ebcdic multifile +000C 3505 ../cp/loader_rdr.bin ../cp/hvf ebcdic multifile # Card Punch 000D 3525 punch00d.txt ascii
--- a/hercules/tape-hvf.tdf Tue Dec 29 20:04:16 2009 -0500 +++ b/hercules/tape-hvf.tdf Fri Jun 18 20:41:48 2010 -0400 @@ -1,4 +1,4 @@ @TDF -/home/jeffpc/hvf/sys/loader_tape.bin FIXED RECSIZE 1024 -/home/jeffpc/hvf/sys/hvf FIXED RECSIZE 4096 +/home/jeffpc/hvf/cp/loader_tape.bin FIXED RECSIZE 1024 +/home/jeffpc/hvf/cp/hvf FIXED RECSIZE 4096 EOT
--- a/include/binfmt_elf.h Tue Dec 29 20:04:16 2009 -0500 +++ b/include/binfmt_elf.h Fri Jun 18 20:41:48 2010 -0400 @@ -1,3 +1,10 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + #ifndef __BINFMT_ELF_H #define __BINFMT_ELF_H
--- a/include/clock.h Tue Dec 29 20:04:16 2009 -0500 +++ b/include/clock.h Fri Jun 18 20:41:48 2010 -0400 @@ -1,3 +1,10 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + #ifndef __CLOCK_H #define __CLOCK_H
--- a/include/digest.h Tue Dec 29 20:04:16 2009 -0500 +++ b/include/digest.h Fri Jun 18 20:41:48 2010 -0400 @@ -1,3 +1,10 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + #ifndef __DIGEST_H #define __DIGEST_H
--- a/include/errno.h Tue Dec 29 20:04:16 2009 -0500 +++ b/include/errno.h Fri Jun 18 20:41:48 2010 -0400 @@ -1,3 +1,10 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + #ifndef __ERRNO_H #define __ERRNO_H
--- a/include/string.h Tue Dec 29 20:04:16 2009 -0500 +++ b/include/string.h Fri Jun 18 20:41:48 2010 -0400 @@ -1,3 +1,10 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + #ifndef __STRING_H #define __STRING_H
--- a/include/types.h Tue Dec 29 20:04:16 2009 -0500 +++ b/include/types.h Fri Jun 18 20:41:48 2010 -0400 @@ -1,3 +1,10 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + #ifndef __TYPES_H #define __TYPES_H
--- a/lib/Makefile Tue Dec 29 20:04:16 2009 -0500 +++ b/lib/Makefile Fri Jun 18 20:41:48 2010 -0400 @@ -7,7 +7,7 @@ digest.a \ string.a -include ../sys/scripts/Makefile.commands +include ../cp/scripts/Makefile.commands all: $(LIBS)
--- a/lib/clock.c Tue Dec 29 20:04:16 2009 -0500 +++ b/lib/clock.c Fri Jun 18 20:41:48 2010 -0400 @@ -1,3 +1,10 @@ +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + #include <clock.h> #define LS_NONE 0x00 /* non-leap second entry */
--- a/lib/string.c Tue Dec 29 20:04:16 2009 -0500 +++ b/lib/string.c Fri Jun 18 20:41:48 2010 -0400 @@ -1,5 +1,10 @@ /* - * Copyright (c) 2007,2008 Josef 'Jeff' Sipek + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + * + * Some of these functions are based on Linux's lib/string.c. */ #include <string.h>
--- a/lib/vsprintf.c Tue Dec 29 20:04:16 2009 -0500 +++ b/lib/vsprintf.c Fri Jun 18 20:41:48 2010 -0400 @@ -1,4 +1,9 @@ /* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + * * A number of things found in this file were borrowed from the Linux Kernel */
--- a/loader/Makefile Tue Dec 29 20:04:16 2009 -0500 +++ b/loader/Makefile Fri Jun 18 20:41:48 2010 -0400 @@ -5,7 +5,7 @@ CFLAGS=-g -fno-strict-aliasing -fno-builtin -nostdlib -Wall -m64 -I ../include/ -O2 -include ../include/types.h NUCLEUSCFLAGS= -include ../sys/scripts/Makefile.commands +include ../cp/scripts/Makefile.commands all: eckd.rto loader.rto
--- a/nss/8ball/8ball.S Tue Dec 29 20:04:16 2009 -0500 +++ b/nss/8ball/8ball.S Fri Jun 18 20:41:48 2010 -0400 @@ -1,6 +1,9 @@ -# -# Copyright (c) 2009 Josef 'Jeff' Sipek -# +/* + * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ # # At this point, the machine is running in ESA390 mode.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/gen-announce-email.sh Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,37 @@ +#!/bin/bash + +USAGE="$0 <rev> <prev_rev>" + +rev="$1" +prev_rev="$2" + +if [ -z "$rev" -o -z "$prev_rev" ]; then + echo $USAGE >&2 + exit 1 +fi + +(cat << DONE +HVF <<REV>> is available for download. + +HVF is a hypervisor OS for z/Architecture systems. + +Tarballs: +http://www.josefsipek.net/projects/hvf/src/ + +Git repo: +git://repo.or.cz/hvf.git + + +<<SUMMARY>> + +As always, patches, and other feedback is welcome. + +Josef "Jeff" Sipek. + +------------ +Changes since <<PREV_REV>>: + +DONE +) | sed -e "s/<<REV>>/$rev/g" -e "s/<<PREV_REV>>/$prev_rev/g" + +git-log --no-merges $prev_rev..$rev | git-shortlog
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/release_version.sh Fri Jun 18 20:41:48 2010 -0400 @@ -0,0 +1,40 @@ +#!/bin/bash + +if [ $# -ne 1 ]; then + echo "Usage: $0 <tagname>" + exit 1 +fi + +case "$1" in + v*) + tag="$1" + ;; + [0-9]*) + tag="v$1" + ;; +esac + +ver=`echo $tag | sed -e 's/^v//'` + +echo "About start release process of '`git rev-parse HEAD`' as '$tag'..." +echo "Press enter to continue." +read n + +echo "1) Edit VERSION in 'Makefile'" +read n +vim Makefile +git update-index Makefile +git commit -s -m "HVF $ver" + +echo "2) Tag the commit with '$tag'" +read n +git tag -u C7958FFE -m "HVF $tag" "$tag" + +echo "3) Generate hvf-$ver.tar.{gz,bz2}" +read n +git archive --format=tar --prefix=hvf-$ver/ HEAD | gzip -9 > hvf-$ver.tar.gz +git archive --format=tar --prefix=hvf-$ver/ HEAD | bzip2 -9 > hvf-$ver.tar.bz2 + +echo "4) Profit" + +echo "We're all done, have a nice day."
--- a/sys/.gitignore Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -*.o -*.rto -ipl/ipl_rdr_ccws.S -ipl/ipl_tape.S -cp/directory_structs.c -hvf -loader_rdr.bin -loader_tape.bin -cscope.out
--- a/sys/Makefile Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -# -# HVF: Hobbyist Virtualization Facility -# - -VERSION=0.16-rc2 - -AS=$(CROSS_COMPILE)as -CC=$(CROSS_COMPILE)gcc -LD=$(CROSS_COMPILE)ld -OBJCOPY=$(CROSS_COMPILE)objcopy - -# By default, be terse -V=0 - -DISPLAYVERSION=$(shell ./scripts/extract-version.sh) - -MAKEFLAGS += -rR --no-print-directory -CFLAGS=-DVERSION=\"$(DISPLAYVERSION)\" -g -fno-strict-aliasing -fno-builtin -nostdlib -Wall -m64 -I include/ -I ../include/ -O2 -include ../include/types.h -NUCLEUSCFLAGS=-include include/nucleus.h -LDFLAGS=-m elf64_s390 - -LIBS=clock digest string - -export AS CC LD OBJCOPY -export MAKEFLAGS CFLAGS NUCLEUSCFLAGS LDFLAGS - -TOP_DIRS=nucleus/ mm/ fs/ drivers/ cp/ - -.PHONY: all build clean mrproper cleanup hvfclean tags -.PHONY: $(TOP_DIRS) - -include scripts/Makefile.commands - -all: build hvf - @echo "Image is `stat -c %s hvf` bytes" - -hvf: $(patsubst %/,%/built-in.o,$(TOP_DIRS)) - $(call link-hvf,$^ $(patsubst %,../lib/%.a,$(LIBS)),$@) - -docs: - ./scripts/gen-docs.sh - -clean: - @$(MAKE) DIR=nucleus/ cleanup V=$V - @$(MAKE) DIR=mm/ cleanup V=$V - @$(MAKE) DIR=fs/ cleanup V=$V - @$(MAKE) DIR=drivers/ cleanup V=$V - @$(MAKE) DIR=cp/ cleanup V=$V - $(call clean,hvf) - $(call clean,cp/directory_structs.c) - $(call rclean,doc/commands) - -mrproper: clean - $(call clean,cscope.out ctags) - -cleanup: - $(call clean,$(DIR)*.o) - -build: $(TOP_DIRS) - -$(TOP_DIRS): %/: - @$(MAKE) -f scripts/Makefile.build DIR=$@ V=$V - -tags: - $(call cscope) - -# -# Include Makefiles from all the top level directories -# -include $(patsubst %/,%/Makefile,$(TOP_DIRS))
--- a/sys/cp/Makefile Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -objs-cp := init.o directory.o cmds.o disassm.o guest.o reset.o intercept.o \ - guest_ipl.o exception.o instruction.o instruction_priv.o splash.o
--- a/sys/cp/cmd_beginstop.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -/* - *!!! BEGIN - *!! SYNTAX - *! \tok{\sc BEgin} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Starts/resumes virtual machine execution. - */ -static int cmd_begin(struct virt_sys *sys, char *cmd, int len) -{ - sys->task->cpu->state = GUEST_OPERATING; - return 0; -} - -/* - *!!! STOP - *!! SYNTAX - *! \tok{\sc STOP} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Stops virtual machine execution. - */ -static int cmd_stop(struct virt_sys *sys, char *cmd, int len) -{ - sys->task->cpu->state = GUEST_STOPPED; - return 0; -}
--- a/sys/cp/cmd_display.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,549 +0,0 @@ -static char* parse_addrspec(u64 *val, u64 *len, char *s) -{ - u64 tmp; - int parsed = 0; - - tmp = 0; - while(!(*s == '\0' || - *s == ' ' || - *s == '\t')) { - if (*s >= '0' && *s <= '9') - tmp = 16*tmp + (*s - '0'); - else if ((*s >= 'A' && *s <= 'F') || - (*s >= 'a' && *s <= 'f')) - tmp = 16*tmp + 10 + ((*s & ~0x20) - 'A'); - else if (*s == '.' && parsed) - break; - else - return ERR_PTR(-EINVAL); - - s++; - parsed = 1; - } - - if (len) { - *len = 0; - if (*s == '.') { - s = __extract_hex(s+1, len); - if (IS_ERR(s)) - parsed = 0; - } - } - - *val = tmp; - - return (parsed == 1 ? s : ERR_PTR(-EINVAL)); -} - -enum display_fmt { - FMT_NUMERIC = 0, - FMT_INSTRUCT, -}; - -static void __display_storage_instruct(struct virt_sys *sys, u64 guest_addr, - u64 mlen) -{ - int ret; - char buf[64]; - int ilen; - u64 val; - u64 host_addr; - - u64 end_addr; - - /* walk the page tables to find the real page frame */ - ret = virt2phy_current(guest_addr, &host_addr); - if (ret) { - con_printf(sys->con, "DISPLAY: Specified address is not part of " - "guest configuration (RC=%d,%d)\n", -EFAULT, ret); - return; - } - - if (!mlen) - mlen = 1; - - end_addr = guest_addr + mlen; - - while(guest_addr < end_addr) { - /* - * FIXME: make sure crossing page-boundary doesn't break - * give us garbage - */ - ilen = disassm((unsigned char*) host_addr, buf, 64); - - if ((host_addr & PAGE_MASK) >= (PAGE_SIZE-ilen)) { - con_printf(sys->con, "DISPLAY: Instruction spans page " - "boundary - not supported\n"); - break; - } - - /* load the dword at the address, and shift it to the LSB part */ - val = *((u64*)host_addr) >> 8*(sizeof(u64) - ilen); - - con_printf(sys->con, "R%016llX %0*llX%*s %s\n", guest_addr, - 2*ilen, val, /* inst hex dump */ - 12-2*ilen, "", /* spacer */ - buf); - - host_addr += ilen; - guest_addr += ilen; - } -} - -static void __display_storage_numeric(struct virt_sys *sys, u64 guest_addr, - u64 mlen) -{ - char buf[80]; - char *bp; - - u64 host_addr; - int this_len; - - int ret; - - /* round down */ - guest_addr &= ~((u64) 0x3); - - /* walk the page tables to find the real page frame */ - ret = virt2phy_current(guest_addr, &host_addr); - if (ret) - goto fault; - - if (mlen > 4) - mlen = (mlen >> 2) + !!(mlen & 0x3); - else - mlen = 1; - - while(mlen && !ret) { - this_len = (mlen > 4) ? 4 : mlen; - - mlen -= this_len; - - bp = buf; - bp += snprintf(bp, 80, "R%016llX ", guest_addr); - - while(this_len) { - bp += snprintf(bp, 80 - (bp - buf), "%08X ", - *(u32*)host_addr); - - guest_addr += 4; - host_addr += 4; - this_len--; - - /* loop if we're not crossing a page, or if we're done */ - if (((guest_addr & PAGE_MASK) != 0) || !mlen) - continue; - - /* - * We will attempt to walk further along guest - * storage, and are about to cross a page boundary, - * walk the page tables to find the real page frame - */ - ret = virt2phy_current(guest_addr, &host_addr); - if (ret) - break; - } - - con_printf(sys->con, "%s\n", buf); - } - -fault: - if (ret) - con_printf(sys->con, "DISPLAY: The address %016llX is not part of " - "guest configuration (RC=%d,%d)\n", guest_addr, -EFAULT, ret); -} - -/* - *!!! DISPLAY STORAGE - *!! SYNTAX - *! \tok{\sc Display} \tok{\sc STOrage} - *! \begin{stack} \\ \deftok{N} \\ \tok{I} \end{stack} - *! <addr> - *! \begin{stack} \\ \tok{.} <length> \end{stack} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Displays a portion of guest's storage. - *!! OPERANDS - *! \cbstart - *! \item[addr] is the guest storage address. - *! \item[length] is the number of bytes to display. If not specified, 4 is - *! assumed. - *! \cbend - *!! SDNAREPO - *!! OPTIONS - *! \cbstart - *! \item[N] display guest storage in numeric format. - *! \item[I] display guest storage in instruction format. - *! \cbend - *!! SNOITPO - *!! NOTES - *! \cbstart - *! \item Currently, the instruction display does not support page-boundary - *! crossing. - *! \cbend - *!! SETON - *!! EXAMPLES - *! D STO 200\\ - *! D STO N200.10\\ - *! D STO I1234.200 - */ -static int cmd_display_storage(struct virt_sys *sys, char *cmd, int len) -{ - u64 guest_addr; - u64 mlen = 0; - enum display_fmt fmt; - - switch (cmd[0]) { - case 'N': case 'n': - /* numeric */ - cmd++; - fmt = FMT_NUMERIC; - break; - case 'I': case 'i': - /* instruction */ - cmd++; - fmt = FMT_INSTRUCT; - break; - default: - /* numeric */ - fmt = FMT_NUMERIC; - break; - } - - cmd = parse_addrspec(&guest_addr, &mlen, cmd); - if (IS_ERR(cmd)) { - con_printf(sys->con, "DISPLAY: Invalid addr-spec\n"); - return 0; - } - - if (fmt == FMT_INSTRUCT) - __display_storage_instruct(sys, guest_addr, mlen); - else - __display_storage_numeric(sys, guest_addr, mlen); - - return 0; -} - -/* - *!!! DISPLAY SIECB - *!! SYNTAX - *! \tok{\sc Display} \tok{\sc SIECB} - *!! XATNYS - *!! AUTH E - *!! PURPOSE - *! Displays hexdump of the guest's SIE control block. - */ -static int cmd_display_siecb(struct virt_sys *sys, char *cmd, int len) -{ - u32 *val; - int i; - - CP_CMD_AUTH(sys, 'E'); - - val = (u32*) &sys->task->cpu->sie_cb; - - for(i=0; i<(sizeof(struct sie_cb)/sizeof(u32)); i+=4) - con_printf(sys->con, "%03lX %08X %08X %08X %08X\n", - i*sizeof(u32), val[i], val[i+1], val[i+2], - val[i+3]); - - return 0; -} - -/* - *!!! DISPLAY GPR - *!! SYNTAX - *! \tok{\sc Display} \tok{\sc Gpr} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Displays the guest's general purpose registers - */ -static int cmd_display_gpr(struct virt_sys *sys, char *cmd, int len) -{ - con_printf(sys->con, "GR 0 = %016llX %016llX\n", - sys->task->cpu->regs.gpr[0], - sys->task->cpu->regs.gpr[1]); - con_printf(sys->con, "GR 2 = %016llX %016llX\n", - sys->task->cpu->regs.gpr[2], - sys->task->cpu->regs.gpr[3]); - con_printf(sys->con, "GR 4 = %016llX %016llX\n", - sys->task->cpu->regs.gpr[4], - sys->task->cpu->regs.gpr[5]); - con_printf(sys->con, "GR 6 = %016llX %016llX\n", - sys->task->cpu->regs.gpr[6], - sys->task->cpu->regs.gpr[7]); - con_printf(sys->con, "GR 8 = %016llX %016llX\n", - sys->task->cpu->regs.gpr[8], - sys->task->cpu->regs.gpr[9]); - con_printf(sys->con, "GR 10 = %016llX %016llX\n", - sys->task->cpu->regs.gpr[10], - sys->task->cpu->regs.gpr[11]); - con_printf(sys->con, "GR 12 = %016llX %016llX\n", - sys->task->cpu->regs.gpr[12], - sys->task->cpu->regs.gpr[13]); - con_printf(sys->con, "GR 14 = %016llX %016llX\n", - sys->task->cpu->regs.gpr[14], - sys->task->cpu->regs.gpr[15]); - return 0; -} - -/* - *!!! DISPLAY FPCR - *!! SYNTAX - *! \tok{\sc Display} \tok{\sc FPCR} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Displays the guest's floating point control register - */ -static int cmd_display_fpcr(struct virt_sys *sys, char *cmd, int len) -{ - con_printf(sys->con, "FPCR = %08X\n", sys->task->cpu->regs.fpcr); - return 0; -} - -/* - *!!! DISPLAY FPR - *!! SYNTAX - *! \tok{\sc Display} \tok{\sc Fpr} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Displays the guest's floating point registers - */ -static int cmd_display_fpr(struct virt_sys *sys, char *cmd, int len) -{ - con_printf(sys->con, "FR 0 = %016llX %016llX\n", - sys->task->cpu->regs.fpr[0], - sys->task->cpu->regs.fpr[1]); - con_printf(sys->con, "FR 2 = %016llX %016llX\n", - sys->task->cpu->regs.fpr[2], - sys->task->cpu->regs.fpr[3]); - con_printf(sys->con, "FR 4 = %016llX %016llX\n", - sys->task->cpu->regs.fpr[4], - sys->task->cpu->regs.fpr[5]); - con_printf(sys->con, "FR 6 = %016llX %016llX\n", - sys->task->cpu->regs.fpr[6], - sys->task->cpu->regs.fpr[7]); - con_printf(sys->con, "FR 8 = %016llX %016llX\n", - sys->task->cpu->regs.fpr[8], - sys->task->cpu->regs.fpr[9]); - con_printf(sys->con, "FR 10 = %016llX %016llX\n", - sys->task->cpu->regs.fpr[10], - sys->task->cpu->regs.fpr[11]); - con_printf(sys->con, "FR 12 = %016llX %016llX\n", - sys->task->cpu->regs.fpr[12], - sys->task->cpu->regs.fpr[13]); - con_printf(sys->con, "FR 14 = %016llX %016llX\n", - sys->task->cpu->regs.fpr[14], - sys->task->cpu->regs.fpr[15]); - return 0; -} - -/* - *!!! DISPLAY CR - *!! SYNTAX - *! \tok{\sc Display} \tok{\sc Cr} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Displays the guest's control registers - */ -static int cmd_display_cr(struct virt_sys *sys, char *cmd, int len) -{ - con_printf(sys->con, "CR 0 = %016llX %016llX\n", - sys->task->cpu->sie_cb.gcr[0], - sys->task->cpu->sie_cb.gcr[1]); - con_printf(sys->con, "CR 2 = %016llX %016llX\n", - sys->task->cpu->sie_cb.gcr[2], - sys->task->cpu->sie_cb.gcr[3]); - con_printf(sys->con, "CR 4 = %016llX %016llX\n", - sys->task->cpu->sie_cb.gcr[4], - sys->task->cpu->sie_cb.gcr[5]); - con_printf(sys->con, "CR 6 = %016llX %016llX\n", - sys->task->cpu->sie_cb.gcr[6], - sys->task->cpu->sie_cb.gcr[7]); - con_printf(sys->con, "CR 8 = %016llX %016llX\n", - sys->task->cpu->sie_cb.gcr[8], - sys->task->cpu->sie_cb.gcr[9]); - con_printf(sys->con, "CR 10 = %016llX %016llX\n", - sys->task->cpu->sie_cb.gcr[10], - sys->task->cpu->sie_cb.gcr[11]); - con_printf(sys->con, "CR 12 = %016llX %016llX\n", - sys->task->cpu->sie_cb.gcr[12], - sys->task->cpu->sie_cb.gcr[13]); - con_printf(sys->con, "CR 14 = %016llX %016llX\n", - sys->task->cpu->sie_cb.gcr[14], - sys->task->cpu->sie_cb.gcr[15]); - return 0; -} - -/* - *!!! DISPLAY AR - *!! SYNTAX - *! \tok{\sc Display} \tok{\sc Ar} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Displays the guest's access registers - */ -static int cmd_display_ar(struct virt_sys *sys, char *cmd, int len) -{ - con_printf(sys->con, "AR 0 = %08X %08X\n", - sys->task->cpu->regs.ar[0], - sys->task->cpu->regs.ar[1]); - con_printf(sys->con, "AR 2 = %08X %08X\n", - sys->task->cpu->regs.ar[2], - sys->task->cpu->regs.ar[3]); - con_printf(sys->con, "AR 4 = %08X %08X\n", - sys->task->cpu->regs.ar[4], - sys->task->cpu->regs.ar[5]); - con_printf(sys->con, "AR 6 = %08X %08X\n", - sys->task->cpu->regs.ar[6], - sys->task->cpu->regs.ar[7]); - con_printf(sys->con, "AR 8 = %08X %08X\n", - sys->task->cpu->regs.ar[8], - sys->task->cpu->regs.ar[9]); - con_printf(sys->con, "AR 10 = %08X %08X\n", - sys->task->cpu->regs.ar[10], - sys->task->cpu->regs.ar[11]); - con_printf(sys->con, "AR 12 = %08X %08X\n", - sys->task->cpu->regs.ar[12], - sys->task->cpu->regs.ar[13]); - con_printf(sys->con, "AR 14 = %08X %08X\n", - sys->task->cpu->regs.ar[14], - sys->task->cpu->regs.ar[15]); - return 0; -} - -/* - *!!! DISPLAY PSW - *!! SYNTAX - *! \tok{\sc Display} \tok{\sc PSW} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Displays the guest's PSW. - *! - *! \cbstart - *! If the guest is in ESA/390 mode, the 8-byte PSW is displayed. - *! - *! If the guest is in z/Architecture mode, the 16-byte PSW is displayed. - *! \cbend - */ -static int cmd_display_psw(struct virt_sys *sys, char *cmd, int len) -{ - u32 *ptr = (u32*) &sys->task->cpu->sie_cb.gpsw; - - if (VCPU_ZARCH(sys->task->cpu)) - con_printf(sys->con, "PSW = %08X %08X %08X %08X\n", - ptr[0], ptr[1], ptr[2], ptr[3]); - else - con_printf(sys->con, "PSW = %08X %08X\n", - ptr[0], ptr[1]); - - return 0; -} - -static void __do_display_schib(struct console *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", - vdev->sch, vdev->pmcw.dev_num, vdev->pmcw.interrupt_param, - vdev->pmcw.isc, ((vdev->pmcw.e << 7) | - (vdev->pmcw.lm << 5) | - (vdev->pmcw.mm << 3) | - (vdev->pmcw.d << 2) | - (vdev->pmcw.t << 1) | - (vdev->pmcw.v)), - vdev->pmcw.lpm, vdev->pmcw.pnom, vdev->pmcw.lpum, - vdev->pmcw.pim, - /* MBI */ - vdev->pmcw.pom, vdev->pmcw.pam, - vdev->pmcw.chpid[0], vdev->pmcw.chpid[1], - vdev->pmcw.chpid[2], vdev->pmcw.chpid[3], - vdev->pmcw.chpid[4], vdev->pmcw.chpid[5], - vdev->pmcw.chpid[6], vdev->pmcw.chpid[7]); -} - -/* - *!!! DISPLAY SCHIB - *!! SYNTAX - *! \tok{\sc Display} \tok{\sc SCHIB} - *! \begin{stack} \tok{ALL} \\ <schib> \end{stack} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Displays the guest's subchannel control block information - */ -static int cmd_display_schib(struct virt_sys *sys, char *cmd, int len) -{ - struct virt_device *vdev; - u64 sch; - int all; - - if (strcasecmp(cmd, "ALL")) { - cmd = __extract_hex(cmd, &sch); - if (IS_ERR(cmd)) - return PTR_ERR(cmd); - - /* sch number must be: X'0001____' */ - if ((sch & 0xffff0000) != 0x00010000) - return -EINVAL; - - all = 0; - } else - all = 1; - - /* find the virtual device */ - - list_for_each_entry(vdev, &sys->virt_devs, devices) { - if ((vdev->sch == (u32) sch) || all) { - if (!all || all == 1) { - con_printf(sys->con, "SCHIB DEV INT-PARM ISC FLG LP " - "PNO LPU PI MBI PO PA CHPID0-3 CHPID4-7\n"); - all = (all ? 2 : 0); - } - - __do_display_schib(sys->con, vdev); - - if (!all) - break; - } - } - - return 0; -} - -static struct cpcmd cmd_tbl_display[] = { - {"AR", cmd_display_ar, NULL}, - {"A", cmd_display_ar, NULL}, - - {"CR", cmd_display_cr, NULL}, - {"C", cmd_display_cr, NULL}, - - {"FPCR", cmd_display_fpcr, NULL}, - - {"FPR", cmd_display_fpr, NULL}, - {"FP", cmd_display_fpr, NULL}, - {"F", cmd_display_fpr, NULL}, - - {"GPR", cmd_display_gpr, NULL}, - {"GP", cmd_display_gpr, NULL}, - {"G", cmd_display_gpr, NULL}, - - {"PSW", cmd_display_psw, NULL}, - - {"SCHIB", cmd_display_schib, NULL}, - - {"SIECB", cmd_display_siecb, NULL}, - - {"STORAGE", cmd_display_storage, NULL}, - {"STORAG", cmd_display_storage, NULL}, - {"STORA", cmd_display_storage, NULL}, - {"STOR", cmd_display_storage, NULL}, - {"STO", cmd_display_storage, NULL}, - {"", NULL, NULL}, -};
--- a/sys/cp/cmd_enable.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - *!!! ENABLE - *!! SYNTAX - *! \tok{\sc ENAble} - *! \begin{stack} \tok{ALL} \\ <rdev> \end{stack} - *!! XATNYS - *!! AUTH A - *!! PURPOSE - *! Enables a real device. - */ -static int cmd_enable(struct virt_sys *sys, char *cmd, int len) -{ - u64 devnum; - struct device *dev; - struct console *con; - - if (!strcasecmp(cmd, "ALL")) { - con_printf(sys->con, "ENABLE ALL not yet implemented!\n"); - return 0; - } - - cmd = __extract_hex(cmd, &devnum); - if (IS_ERR(cmd)) - return PTR_ERR(cmd); - - /* device number must be 16-bit */ - if (devnum & ~0xffffUL) - return -EINVAL; - - dev = find_device_by_ccuu(devnum); - if (IS_ERR(dev)) { - con_printf(sys->con, "Device %04llX not found in configuration\n", devnum); - return 0; - } - - if (atomic_read(&dev->in_use)) { - con_printf(sys->con, "Device %04llX is already in use\n", devnum); - dev_put(dev); - return 0; - } - - if (!dev->dev->enable) { - con_printf(sys->con, "Device type %-4s cannot be enabled\n", - type2name(dev->type)); - return 0; - } - - con = dev->dev->enable(dev); - if (IS_ERR(con)) { - con_printf(sys->con, "Failed to enable %04llX\n", devnum); - return PTR_ERR(con); - } - - return 0; -}
--- a/sys/cp/cmd_helpers.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -static char* __extract_dec(char *str, u64 *val) -{ - u64 res; - u64 tmp; - int len; - - if (!str || !val) - return ERR_PTR(-EINVAL); - - res = 0; - len = -1; - - for (; str && *str != '\0'; str++, len++) { - if (*str >= '0' && *str <= '9') - tmp = *str - '0'; - else if (*str == ' ' || *str == '\t') - break; - else - return ERR_PTR(-EINVAL); - - res = (res * 10) + tmp; - } - - if (len == -1) - return ERR_PTR(-EINVAL); - - *val = res; - - return str; -} - -static char* __extract_hex(char *str, u64 *val) -{ - u64 res; - u64 tmp; - int len; - - if (!str || !val) - return ERR_PTR(-EINVAL); - - res = 0; - len = -1; - - for (; str && *str != '\0'; str++, len++) { - if (*str >= '0' && *str <= '9') - tmp = *str - '0'; - else if (*str >= 'A' && *str <= 'F') - tmp = *str - 'A' + 10; - else if (*str >= 'a' && *str <= 'f') - tmp = *str - 'a' + 10; - else if (*str == ' ' || *str == '\t') - break; - else - return ERR_PTR(-EINVAL); - - res = (res << 4) | tmp; - } - - if (len == -1) - return ERR_PTR(-EINVAL); - - *val = res; - - return str; -} - -static char* __consume_ws(char *str) -{ - if (!str) - return str; - - /* consume any extra whitespace */ - while(*str == ' ' || *str == '\t') - str++; - - return str; -}
--- a/sys/cp/cmd_logon.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - *!!! LOGON - *!! SYNTAX - *! \tok{\sc LOGON} <userid> - *!! XATNYS - *!! AUTH G - *!! 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_cp(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) -{ - con_printf(sys->con, "ALREADY LOGGED ON\n"); - return 0; -}
--- a/sys/cp/cmd_query.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,261 +0,0 @@ -static char *__guest_state_to_str(enum virt_cpustate st) -{ - switch (st) { - case GUEST_STOPPED: return "STOPPED"; - case GUEST_OPERATING: return "RUNNING"; - case GUEST_LOAD: return "LOADING"; - case GUEST_CHECKSTOP: return "CHECK-STOP"; - } - - return "???"; -} - -static void display_rdev(struct console *con, struct device *dev) -{ - char buf[40]; - - buf[0] = '\0'; - - 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->sch); -} - -static void display_vdev(struct console *con, struct virt_device *vdev) -{ - switch (vdev->vtype) { - case VDEV_CONS: - con_printf(con, "CONS %04X 3215 ON %s %04X %s SCH = %05X\n", - vdev->pmcw.dev_num, - type2name(con->dev->type), // FIXME? - con->dev->ccuu, - con->sys->print_ts ? "TS" : "NOTS", - vdev->sch); - break; - case VDEV_DED: - con_printf(con, "%-4s %04X %04X ON DEV %04X SCH = %05X\n", - type2name(vdev->type), - vdev->pmcw.dev_num, - vdev->type, - vdev->u.dedicate.rdev->ccuu, - vdev->sch); - break; - case VDEV_SPOOL: - con_printf(con, "%-4s %04X %04X SCH = %05X\n", - type2name(vdev->type), - vdev->pmcw.dev_num, vdev->type, - vdev->sch); - break; - case VDEV_MDISK: - con_printf(con, "DASD %04X 3390 %6d CYL ON DASD %04X SCH = %05X\n", - vdev->pmcw.dev_num, - 0, /* FIXME: cyl count */ - 0, /* FIXME: rdev */ - vdev->sch); - break; - case VDEV_LINK: - con_printf(con, "LINK %04X TO %s %04X SCH = %05X\n", - vdev->pmcw.dev_num, - "????", /* FIXME: userid */ - 0xffff, /* FIXME: user's vdev # */ - vdev->sch); - break; - default: - con_printf(con, "???? unknown device type (%04X, %05X)\n", - vdev->pmcw.dev_num, vdev->sch); - break; - } -} - -static void display_task(struct console *con, struct task *task) -{ - char state; - - switch(task->state) { - case TASK_RUNNING: state = 'R'; break; - case TASK_SLEEPING: state = 'S'; break; - case TASK_LOCKED: state = 'L'; break; - default: state = '?'; break; - } - - con_printf(con, "%*s %p %c %016llX\n", -TASK_NAME_LEN, task->name, - task, state, task->regs.psw.ptr); -} - -/* - *!!! QUERY TIME - *!! SYNTAX - *! \tok{\sc Query} \tok{\sc TIME} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Displays the current time - */ -static int cmd_query_cplevel(struct virt_sys *sys, char *cmd, int len) -{ - con_printf(sys->con, "HVF version " VERSION "\n"); - con_printf(sys->con, "IPL at %02d:%02d:%02d UTC %04d-%02d-%02d\n", - ipltime.th, ipltime.tm, ipltime.ts, ipltime.dy, - ipltime.dm, ipltime.dd); - - return 0; -} - -/* - *!!! QUERY CPLEVEL - *!! SYNTAX - *! \tok{\sc Query} \tok{\sc CPLEVEL} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Displays the HVF version and time of IPL - */ -static int cmd_query_time(struct virt_sys *sys, char *cmd, int len) -{ - struct datetime dt; - - get_parsed_tod(&dt); - - con_printf(sys->con, "TIME IS %02d:%02d:%02d UTC %04d-%02d-%02d\n", - dt.th, dt.tm, dt.ts, dt.dy, dt.dm, dt.dd); - - return 0; -} - -/* - *!!! QUERY ARCHMODE - *!! SYNTAX - *! \tok{\sc Query} \tok{\sc ARCHMODE} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Displays the virtual machine's current architecture mode. - */ -static int cmd_query_archmode(struct virt_sys *sys, char *cmd, int len) -{ - char *mode = (VCPU_ZARCH(sys->task->cpu)) ? "z/Arch" : "ESA390"; - - con_printf(sys->con, "ARCHMODE = %s\n", mode); - - return 0; -} - -/* - *!!! QUERY VIRTUAL - *!! SYNTAX - *! \tok{\sc Query} \tok{\sc Virtual} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Lists all of the guest's virtual devices - */ -static int cmd_query_virtual(struct virt_sys *sys, char *cmd, int len) -{ - struct virt_device *vdev; - - con_printf(sys->con, "CPU 00 ID %016llX %s\n", - sys->task->cpu->cpuid, - __guest_state_to_str(sys->task->cpu->state)); - con_printf(sys->con, "STORAGE = %lluM\n", sys->directory->storage_size >> 20); - - list_for_each_entry(vdev, &sys->virt_devs, devices) - display_vdev(sys->con, vdev); - - return 0; -} - -/* - *!!! QUERY REAL - *!! SYNTAX - *! \tok{\sc Query} \tok{\sc Real} - *!! XATNYS - *!! AUTH A - *!! PURPOSE - *! Lists all of the host's real devices - */ -static int cmd_query_real(struct virt_sys *sys, char *cmd, int len) -{ - CP_CMD_AUTH(sys, 'A'); - - con_printf(sys->con, "CPU %02d ID %016llX RUNNING\n", - getcpuaddr(), - getcpuid()); - con_printf(sys->con, "STORAGE = %lluM\n", memsize >> 20); - - list_devices(sys->con, display_rdev); - - return 0; -} - -/* - *!!! QUERY TASK - *!! SYNTAX - *! \tok{\sc Query} \tok{\sc Task} - *!! XATNYS - *!! AUTH A - *!! PURPOSE - *! Lists all of the tasks running on the host. This includes guest virtual - *! cpu tasks, as well as system helper tasks. - */ -static int cmd_query_task(struct virt_sys *sys, char *cmd, int len) -{ - CP_CMD_AUTH(sys, 'A'); - - list_tasks(sys->con, display_task); - - return 0; -} - -static void display_names(struct console *con, struct virt_sys *sys) -{ - con_printf(con, "%s %04X %-8s\n", type2name(sys->con->dev->type), - sys->con->dev->ccuu, sys->directory->userid); -} - -/* - *!!! QUERY NAMES - *!! SYNTAX - *! \tok{\sc Query} \tok{\sc NAMes} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Lists all of the logged in users. - */ -static int cmd_query_names(struct virt_sys *sys, char *cmd, int len) -{ - list_users(sys->con, display_names); - - return 0; -} - -static struct cpcmd cmd_tbl_query[] = { - {"ARCHMODE", cmd_query_archmode, NULL}, - - {"CPLEVEL", cmd_query_cplevel, NULL}, - - {"TIME", cmd_query_time, NULL}, - - {"VIRTUAL", cmd_query_virtual, NULL}, - {"VIRTUA", cmd_query_virtual, NULL}, - {"VIRTU", cmd_query_virtual, NULL}, - {"VIRT", cmd_query_virtual, NULL}, - {"VIR", cmd_query_virtual, NULL}, - {"VI", cmd_query_virtual, NULL}, - {"V", cmd_query_virtual, NULL}, - - {"REAL", cmd_query_real, NULL}, - {"REA", cmd_query_real, NULL}, - {"RE", cmd_query_real, NULL}, - {"R", cmd_query_real, NULL}, - - {"NAMES", cmd_query_names, NULL}, - {"NAME", cmd_query_names, NULL}, - {"NAM", cmd_query_names, NULL}, - - {"TASK", cmd_query_task, NULL}, - {"", NULL, NULL}, -};
--- a/sys/cp/cmd_set.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - *!!! SET NOTS - *!! SYNTAX - *! \tok{\sc SET} \tok{\sc NOTS} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Disable the console timestamp printing - */ -static int cmd_set_nots(struct virt_sys *sys, char *cmd, int len) -{ - sys->print_ts = 0; - return 0; -} - -/* - *!!! SET TS - *!! SYNTAX - *! \tok{\sc SET} \tok{\sc TS} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Enable the console timestamp printing - */ -static int cmd_set_ts(struct virt_sys *sys, char *cmd, int len) -{ - sys->print_ts = 1; - return 0; -} - -static struct cpcmd cmd_tbl_set[] = { - {"NOTS", cmd_set_nots, NULL}, - {"TS", cmd_set_ts, NULL}, - {"", NULL, NULL}, -};
--- a/sys/cp/cmd_store.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,348 +0,0 @@ -/* - *!!! STORE STORAGE - *!! SYNTAX - *! \cbstart - *! \tok{\sc STOre} \tok{\sc STOrage} <address> <value> - *! \cbend - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Sets a word in guest's storage at address to value - */ -static int cmd_store_storage(struct virt_sys *sys, char *cmd, int len) -{ - int ret; - u64 guest_addr, host_addr; - u64 val = 0; - - cmd = parse_addrspec(&guest_addr, NULL, cmd); - if (IS_ERR(cmd)) { - con_printf(sys->con, "STORE: Invalid addr-spec\n"); - return PTR_ERR(cmd); - } - - /* consume any extra whitespace */ - cmd = __consume_ws(cmd); - - /* get the value */ - cmd = __extract_hex(cmd, &val); - if (IS_ERR(cmd)) - return PTR_ERR(cmd); - - /* - * round down to the nearest word - */ - guest_addr &= ~((u64) 3ULL); - - /* walk the page tables to find the real page frame */ - ret = virt2phy_current(guest_addr, &host_addr); - if (ret) { - con_printf(sys->con, "STORE: Specified address is not part of " - "guest configuration\n"); - return ret; - } - - *((u32*) host_addr) = (u32) val; - - con_printf(sys->con, "Store complete.\n"); - - return 0; -} - -/* - *!!! STORE GPR - *!! SYNTAX - *! \tok{\sc STOre} \tok{\sc Gpr} <gpr> <value> - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Sets a guest's general purpose register to the specified value - */ -static int cmd_store_gpr(struct virt_sys *sys, char *cmd, int len) -{ - u64 *ptr = (u64*) &sys->task->cpu->regs.gpr; - u64 val, gpr; - - cmd = __extract_dec(cmd, &gpr); - if (IS_ERR(cmd)) - return PTR_ERR(cmd); - if (gpr > 15) - return -EINVAL; - - cmd = __consume_ws(cmd); - - cmd = __extract_hex(cmd, &val); - if (IS_ERR(cmd)) - return PTR_ERR(cmd); - - ptr[gpr] = val; - - con_printf(sys->con, "Store complete.\n"); - - return 0; -} - -/* - *!!! STORE FPR - *!! SYNTAX - *! \tok{\sc STOre} \tok{\sc Fpr} <fpr> <value> - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Sets a guest's floating point register to the specified value - */ -static int cmd_store_fpr(struct virt_sys *sys, char *cmd, int len) -{ - u64 *ptr = (u64*) &sys->task->cpu->regs.fpr; - u64 val, fpr; - - cmd = __extract_dec(cmd, &fpr); - if (IS_ERR(cmd)) - return PTR_ERR(cmd); - if (fpr > 15) - return -EINVAL; - - cmd = __consume_ws(cmd); - - cmd = __extract_hex(cmd, &val); - if (IS_ERR(cmd)) - return PTR_ERR(cmd); - - ptr[fpr] = val; - - con_printf(sys->con, "Store complete.\n"); - - return 0; -} - -/* - *!!! STORE FPCR - *!! SYNTAX - *! \tok{\sc STOre} \tok{\sc FPCR} <value> - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Sets a guest's floating point control register to the specified value - */ -static int cmd_store_fpcr(struct virt_sys *sys, char *cmd, int len) -{ - u64 val; - - cmd = __extract_hex(cmd, &val); - if (IS_ERR(cmd)) - return PTR_ERR(cmd); - if (val > 0xffffffffULL) - return -EINVAL; - - sys->task->cpu->regs.fpcr = (u32) val; - - con_printf(sys->con, "Store complete.\n"); - - return 0; -} - -/* - *!!! STORE CR - *!! SYNTAX - *! \tok{\sc STOre} \tok{\sc Cr} <cr> <value> - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Sets a guest's control register to the specified value - */ -static int cmd_store_cr(struct virt_sys *sys, char *cmd, int len) -{ - u64 *ptr = (u64*) &sys->task->cpu->sie_cb.gcr; - u64 val, cr; - - cmd = __extract_dec(cmd, &cr); - if (IS_ERR(cmd)) - return PTR_ERR(cmd); - if (cr > 15) - return -EINVAL; - - cmd = __consume_ws(cmd); - - cmd = __extract_hex(cmd, &val); - if (IS_ERR(cmd)) - return PTR_ERR(cmd); - - ptr[cr] = val; - - con_printf(sys->con, "Store complete.\n"); - - return 0; -} - -/* - *!!! STORE AR - *!! SYNTAX - *! \tok{\sc STOre} \tok{\sc Ar} <ar> <value> - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Sets a guest's access register to the specified value - */ -static int cmd_store_ar(struct virt_sys *sys, char *cmd, int len) -{ - u32 *ptr = (u32*) &sys->task->cpu->regs.ar; - u64 val, ar; - - cmd = __extract_dec(cmd, &ar); - if (IS_ERR(cmd)) - return PTR_ERR(cmd); - if (ar > 15) - return -EINVAL; - - cmd = __consume_ws(cmd); - - cmd = __extract_hex(cmd, &val); - if (IS_ERR(cmd)) - return PTR_ERR(cmd); - if (val > 0xffffffffULL) - return -EINVAL; - - ptr[ar] = val; - - con_printf(sys->con, "Store complete.\n"); - - return 0; -} - -/* - *!!! STORE PSW - *!! SYNTAX - *! \cbstart - *! \tok{\sc STOre} \tok{\sc PSW} - *! \begin{stack} \\ - *! \begin{stack} \\ - *! \begin{stack} \\ <hexword1> - *! \end{stack} <hexword2> - *! \end{stack} <hexword3> - *! \end{stack} - *! <hexword4> - *! \cbend - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! \cbstart - *! Alters all or a part of the PSW. - *! \cbend - *!! OPERANDS - *! \cbstart - *! \item[hexword...] - *! \textbf{For an ESA/390 guest:} - *! - *! Alters all or part of the PSW with the data specified in hexword1 - *! and hexword2. If only hexword2 is specified, it is stored to PSW bits - *! 32-63. If hexword3 and hexword4 are specified, hexword3 is stored to - *! PSW bits 0-31, and hexword4 to PSW bits 32-63. - *! - *! If more than two values are specified, the PSW remains unchanged and an - *! message indicating an error is printed. - *! - *! \textbf{For a z/Architecture guest:} - *! - *! If only one hexword4 is specified, PSW bits 96-127 are set to it. - *! - *! If hexword3 and hexword4 are specified, PSW bits 64-95 are set to - *! hexword3, and bits 96-127 are set to hexword4. - *! - *! If hexword2, hexword3, and hexword4 are specified, PSW bits 32-63 are - *! set to hexword2, bits 64-95 are set to hexword3, and bits 96-127 are - *! set to hexword4. - *! - *! If hexword1, hexword2, hexword3, and hexword4 are specified, PSW bits - *! 0-31 are set to hexword1, bits 32-63 are set to hexword2, bits 64-95 - *! are set to hexword3, and bits 96-127 are set to hexword4. - *! \cbend - *!! SDNAREPO - */ -static int cmd_store_psw(struct virt_sys *sys, char *cmd, int len) -{ - u32 *ptr = (u32*) &sys->task->cpu->sie_cb.gpsw; - - u64 new_words[4] = {0, 0, 0, 0}; - int cnt; - - for (cnt=0; cnt<4; cnt++) { - cmd = __extract_hex(cmd, &new_words[cnt]); - if (IS_ERR(cmd)) - break; - - cmd = __consume_ws(cmd); - } - - if (!cnt) - return -EINVAL; - - if (!VCPU_ZARCH(sys->task->cpu)) { - /* ESA/390 mode */ - if (cnt > 2) { - con_printf(sys->con, "STORE: ERROR ESA/390 PSW USES ONLY TWO WORDS\n"); - return -EINVAL; - } - - /* - * This is a simple "hack" to make the stores go into the - * right place. If he had a single word, we want it to go - * the the second word of the 16-byte PSW, not the 4th. - * Similarly, if we had two words, we want them to go into - * the first and second words of the 16-byte PSW. - */ - cnt += 2; - } - - switch(cnt) { - case 4: - ptr[0] = (u32) new_words[0]; - ptr[1] = (u32) new_words[1]; - ptr[2] = (u32) new_words[2]; - ptr[3] = (u32) new_words[3]; - break; - case 3: - ptr[1] = (u32) new_words[0]; - ptr[2] = (u32) new_words[1]; - ptr[3] = (u32) new_words[2]; - break; - case 2: - ptr[2] = (u32) new_words[0]; - ptr[3] = (u32) new_words[1]; - break; - case 1: - ptr[3] = (u32) new_words[0]; - break; - case 0: - return -EINVAL; - } - - con_printf(sys->con, "Store complete.\n"); - return 0; -} - -static struct cpcmd cmd_tbl_store[] = { - {"AR", cmd_store_ar, NULL}, - {"A", cmd_store_ar, NULL}, - - {"CR", cmd_store_cr, NULL}, - {"C", cmd_store_cr, NULL}, - - {"FPCR", cmd_store_fpcr, NULL}, - - {"FPR", cmd_store_fpr, NULL}, - {"FP", cmd_store_fpr, NULL}, - {"F", cmd_store_fpr, NULL}, - - {"GPR", cmd_store_gpr, NULL}, - {"GP", cmd_store_gpr, NULL}, - {"G", cmd_store_gpr, NULL}, - - {"PSW", cmd_store_psw, NULL}, - - {"STORAGE", cmd_store_storage, NULL}, - {"STORAG", cmd_store_storage, NULL}, - {"STORA", cmd_store_storage, NULL}, - {"STOR", cmd_store_storage, NULL}, - {"STO", cmd_store_storage, NULL}, - {"", NULL, NULL}, -};
--- a/sys/cp/cmd_system.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -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) -{ - struct virt_device *vdev; - u64 vdevnum = 0; - 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"); - - /* - * 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; -} - -/*!!! 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) -{ - 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; -}
--- a/sys/cp/cmds.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,170 +0,0 @@ -#include <directory.h> -#include <vdevice.h> -#include <dat.h> -#include <mm.h> -#include <sched.h> -#include <disassm.h> -#include <cp.h> -#include <cpu.h> -#include <vsprintf.h> - -struct cpcmd { - const char name[CP_CMD_MAX_LEN]; - - /* handle function pointer */ - int (*fnx)(struct virt_sys *sys, char *cmd, int len); - - /* sub-command handler table */ - struct cpcmd *sub; -}; - -/* - * Map a device type to a nice to display name - */ -static char* type2name(u16 type) -{ - switch (type) { - case 0x1403: return "PRT"; - case 0x1732: return "OSA"; - case 0x3088: return "CTCA"; - case 0x3215: return "CONS"; - case 0x3278: return "GRAF"; - case 0x3505: return "RDR"; - case 0x3525: return "PUN"; - - /* various dasds */ - case 0x3390: - case 0x9336: return "DASD"; - - /* various tape drives */ - case 0x3480: - case 0x3490: - case 0x3590: return "TAPE"; - - default: return "????"; - } -} - -/* - * We use includes here to avoid namespace polution with all the sub-command - * 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_set.c" - -static struct cpcmd commands[] = { - {"BEGIN", cmd_begin, NULL}, - {"BEGI", cmd_begin, NULL}, - {"BEG", cmd_begin, NULL}, - {"BE", cmd_begin, NULL}, - - {"DISPLAY", NULL, cmd_tbl_display}, - {"DISPLA", NULL, cmd_tbl_display}, - {"DISPL", NULL, cmd_tbl_display}, - {"DISP", NULL, cmd_tbl_display}, - {"DIS", NULL, cmd_tbl_display}, - {"DI", NULL, cmd_tbl_display}, - {"D", NULL, cmd_tbl_display}, - - {"ENABLE", cmd_enable, NULL}, - {"ENABL", cmd_enable, NULL}, - {"ENAB", cmd_enable, NULL}, - {"ENA", cmd_enable, NULL}, - - {"IPL", cmd_ipl, NULL}, - {"IP", cmd_ipl, NULL}, - {"I", cmd_ipl, NULL}, - - {"LOGON", cmd_logon_fail, NULL}, - {"LOGO", cmd_logon_fail, NULL}, - {"LOG", cmd_logon_fail, NULL}, - {"LO", cmd_logon_fail, NULL}, - {"L", cmd_logon_fail, NULL}, - - {"QUERY", NULL, cmd_tbl_query}, - {"QUER", NULL, cmd_tbl_query}, - {"QUE", NULL, cmd_tbl_query}, - {"QU", NULL, cmd_tbl_query}, - {"Q", NULL, cmd_tbl_query}, - - {"SET", NULL, cmd_tbl_set}, - - {"STOP", cmd_stop, NULL}, - - {"STORE", NULL, cmd_tbl_store}, - {"STOR", NULL, cmd_tbl_store}, - {"STO", NULL, cmd_tbl_store}, - - {"SYSTEM", cmd_system, NULL}, - {"SYSTE", cmd_system, NULL}, - {"SYST", cmd_system, NULL}, - {"SYS", cmd_system, NULL}, - {"", NULL, NULL}, -}; - -static struct cpcmd logon_commands[] = { - {"LOGON", cmd_logon, NULL}, - {"LOGO", cmd_logon, NULL}, - {"LOG", cmd_logon, NULL}, - {"LO", cmd_logon, NULL}, - {"L", cmd_logon, NULL}, - {"", NULL, NULL}, -}; - -static int __invoke_cp_cmd(struct cpcmd *t, struct virt_sys *sys, char *cmd, int len) -{ - int i, ret; - - for(i=0; t[i].name[0]; i++) { - const char *inp = cmd, *exp = t[i].name; - int match_len = 0; - - while(*inp && *exp && (match_len < len) && (toupper(*inp) == *exp)) { - match_len++; - inp++; - exp++; - } - - /* doesn't match */ - if ((match_len != strnlen(t[i].name, CP_CMD_MAX_LEN)) || - (!isspace(*inp) && *inp)) - continue; - - /* - * the next char in the input is... - */ - while((cmd[match_len] == ' ' || cmd[match_len] == '\t') && - (match_len < len)) - /* - * command was given arguments - skip over the - * delimiting space - */ - match_len++; - - if (t[i].sub) { - ret = __invoke_cp_cmd(t[i].sub, sys, cmd + match_len, len - match_len); - return (ret == -ENOENT) ? -ESUBENOENT : ret; - } - - return t[i].fnx(sys, cmd + match_len, len - match_len); - } - - return -ENOENT; -} - -int invoke_cp_cmd(struct virt_sys *sys, char *cmd, int len) -{ - return __invoke_cp_cmd(commands, sys, cmd, len); -} - -int invoke_cp_logon(struct console *con, char *cmd, int len) -{ - return __invoke_cp_cmd(logon_commands, (struct virt_sys*) con, cmd, len); -}
--- a/sys/cp/directory.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -#include <errno.h> -#include <directory.h> - -#include "directory_structs.c" - -struct user *find_user_by_id(char *userid) -{ - struct user *u; - - if (!userid) - return ERR_PTR(-ENOENT); - - u = directory; - - for (; u->userid; u++) - if (!strcasecmp(u->userid, userid)) - return u; - - return ERR_PTR(-ENOENT); -}
--- a/sys/cp/disassm.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1091 +0,0 @@ -#include <disassm.h> -#include <vsprintf.h> - -static struct disassm_instruction l2_01[256] = { /* 01xx */ - DA_INST (0x01, E, PR), - DA_INST (0x02, E, UPT), - DA_INST (0x04, E, PTFF), - DA_INST (0x07, E, SCKPF), - DA_INST (0x0A, E, PFPO), - DA_INST (0x0B, E, TAM), - DA_INST (0x0C, E, SAM24), - DA_INST (0x0D, E, SAM31), - DA_INST (0x0E, E, SAM64), - DA_INST (0xFF, E, TRAP2), -}; - -static struct disassm_instruction l2_a5[16] = { /* A5x */ - DA_INST (0x0, RI1, IIHH), - DA_INST (0x1, RI1, IIHL), - DA_INST (0x2, RI1, IILH), - DA_INST (0x3, RI1, IILL), - DA_INST (0x4, RI1, NIHH), - DA_INST (0x5, RI1, NIHL), - DA_INST (0x6, RI1, NILH), - DA_INST (0x7, RI1, NILL), - DA_INST (0x8, RI1, OIHH), - DA_INST (0x9, RI1, OIHL), - DA_INST (0xA, RI1, OILH), - DA_INST (0xB, RI1, OILL), - DA_INST (0xC, RI1, LLIHH), - DA_INST (0xD, RI1, LLIHL), - DA_INST (0xE, RI1, LLILH), - DA_INST (0xF, RI1, LLILL), -}; - -static struct disassm_instruction l2_a7[16] = { /* A7x */ - DA_INST (0x0, RI1, TMLH), - DA_INST (0x1, RI1, TMLL), - DA_INST (0x2, RI1, TMHH), - DA_INST (0x3, RI1, TMHL), - DA_INST (0x4, RI2, BRC), - DA_INST (0x5, RI1, BRAS), - DA_INST (0x6, RI1, BRCT), - DA_INST (0x7, RI1, BRCTG), - DA_INST (0x8, RI1, LHI), - DA_INST (0x9, RI1, LGHI), - DA_INST (0xA, RI1, AHI), - DA_INST (0xB, RI1, AGHI), - DA_INST (0xC, RI1, MHI), - DA_INST (0xD, RI1, MGHI), - DA_INST (0xE, RI1, CHI), - DA_INST (0xF, RI1, CGHI), -}; - -static struct disassm_instruction l2_b2[256] = { /* B2xx */ - DA_INST (0x02, S, STIDP), - DA_INST (0x04, S, SCK), - DA_INST (0x05, S, STCK), - DA_INST (0x06, S, SCKC), - DA_INST (0x07, S, STCKC), - DA_INST (0x08, S, SPT), - DA_INST (0x09, S, STPT), - DA_INST (0x0A, S, SPKA), - DA_INST (0x0B, S, IPK), - DA_INST (0x0D, S, PTLB), - DA_INST (0x10, S, SPX), - DA_INST (0x11, S, STPX), - DA_INST (0x12, S, STAP), - DA_INST (0x14, S, SIE), - DA_INST (0x18, S, PC), - DA_INST (0x19, S, SAC), - DA_INST (0x1A, S, CFC), - DA_INST (0x21, RRE, IPTE), - DA_INST (0x22, RRE, IPM), - DA_INST (0x23, RRE, IVSK), - DA_INST (0x24, RRE, IAC), - DA_INST (0x25, RRE, SSAR), - DA_INST (0x26, RRE, EPAR), - DA_INST (0x27, RRE, ESAR), - DA_INST (0x28, RRE, PT), - DA_INST (0x29, RRE, ISKE), - DA_INST (0x2A, RRE, RRBE), - DA_INST (0x2B, RRF2, SSKE), - DA_INST (0x2C, RRE, TB), - DA_INST (0x2D, RRE, DXR), - DA_INST (0x2E, RRE, PGIN), - DA_INST (0x2F, RRE, PGOUT), - DA_INST (0x30, S, CSCH), - DA_INST (0x31, S, HSCH), - DA_INST (0x32, S, MSCH), - DA_INST (0x33, S, SSCH), - DA_INST (0x34, S, STSCH), - DA_INST (0x35, S, TSCH), - DA_INST (0x36, S, TPI), - DA_INST (0x37, S, SAL), - DA_INST (0x38, S, RSCH), - DA_INST (0x39, S, STCRW), - DA_INST (0x3A, S, STCPS), - DA_INST (0x3B, S, RCHP), - DA_INST (0x3D, S, SCHM), - DA_INST (0x40, RRE, BAKR), - DA_INST (0x41, RRE, CKSM), - DA_INST (0x44, RRE, SQDR), - DA_INST (0x45, RRE, SQER), - DA_INST (0x46, RRE, STURA), - DA_INST (0x47, RRE, MSTA), - DA_INST (0x48, RRE, PALB), - DA_INST (0x49, RRE, EREG), - DA_INST (0x4A, RRE, ESTA), - DA_INST (0x4B, RRE, LURA), - DA_INST (0x4C, RRE, TAR), - DA_INST (0x4D, RRE, CPYA), - DA_INST (0x4E, RRE, SAR), - DA_INST (0x4F, RRE, EAR), - DA_INST (0x50, RRE, CSP), - DA_INST (0x52, RRE, MSR), - DA_INST (0x54, RRE, MVPG), - DA_INST (0x55, RRE, MVST), - DA_INST (0x57, RRE, CUSE), - DA_INST (0x58, RRE, BSG), - DA_INST (0x5A, RRE, BSA), - DA_INST (0x5D, RRE, CLST), - DA_INST (0x5E, RRE, SRST), - DA_INST (0x63, RRE, CMPSC), - DA_INST (0x76, S, XSCH), - DA_INST (0x77, S, RP), - DA_INST (0x78, S, STCKE), - DA_INST (0x79, S, SACF), - DA_INST (0x7C, S, STCKF), - DA_INST (0x7D, S, STSI), - DA_INST (0x99, S, SRNM), - DA_INST (0x9C, S, STFPC), - DA_INST (0x9D, S, LFPC), - DA_INST (0xA5, RRE, TRE), - DA_INST (0xA6, RRF2, CUUTF), - DA_INST (0xA7, RRF2, CUTFU), - DA_INST (0xB0, S, STFLE), - DA_INST (0xB1, S, STFL), - DA_INST (0xB2, S, LPSWE), - DA_INST (0xB9, S, SRNMT), - DA_INST (0xBD, S, LFAS), - DA_INST (0xFF, S, TRAP4), -}; - -static struct disassm_instruction l2_b3[256] = { /* B3xx */ - DA_INST (0x00, RRE, LPEBR), - DA_INST (0x01, RRE, LNEBR), - DA_INST (0x02, RRE, LTEBR), - DA_INST (0x03, RRE, LCEBR), - DA_INST (0x04, RRE, LDEBR), - DA_INST (0x05, RRE, LXDBR), - DA_INST (0x06, RRE, LXEBR), - DA_INST (0x07, RRE, MXDBR), - DA_INST (0x08, RRE, KEBR), - DA_INST (0x09, RRE, CEBR), - DA_INST (0x0A, RRE, AEBR), - DA_INST (0x0B, RRE, SEBR), - DA_INST (0x0C, RRE, MDEBR), - DA_INST (0x0D, RRE, DEBR), - DA_INST (0x0E, RRF1, MAEBR), - DA_INST (0x0F, RRF1, MSEBR), - DA_INST (0x10, RRE, LPDBR), - DA_INST (0x11, RRE, LNDBR), - DA_INST (0x12, RRE, LTDBR), - DA_INST (0x13, RRE, LCDBR), - DA_INST (0x14, RRE, SQEBR), - DA_INST (0x15, RRE, SQDBR), - DA_INST (0x16, RRE, SQXBR), - DA_INST (0x17, RRE, MEEBR), - DA_INST (0x18, RRE, KDBR), - DA_INST (0x19, RRE, CDBR), - DA_INST (0x1A, RRE, ADBR), - DA_INST (0x1B, RRE, SDBR), - DA_INST (0x1C, RRE, MDBR), - DA_INST (0x1D, RRE, DDBR), - DA_INST (0x1E, RRF1, MADBR), - DA_INST (0x1F, RRF1, MSDBR), - DA_INST (0x24, RRE, LDER), - DA_INST (0x25, RRE, LXDR), - DA_INST (0x26, RRE, LXER), - DA_INST (0x2E, RRF1, MAER), - DA_INST (0x2F, RRF1, MSER), - DA_INST (0x36, RRE, SQXR), - DA_INST (0x37, RRE, MEER), - DA_INST (0x38, RRF1, MAYLR), - DA_INST (0x39, RRF1, MYLR), - DA_INST (0x3A, RRF1, MAYR), - DA_INST (0x3B, RRF1, MYR), - DA_INST (0x3C, RRF1, MAYHR), - DA_INST (0x3D, RRF1, MYHR), - DA_INST (0x3E, RRF1, MADR), - DA_INST (0x3F, RRF1, MSDR), - DA_INST (0x40, RRE, LPXBR), - DA_INST (0x41, RRE, LNXBR), - DA_INST (0x42, RRE, LTXBR), - DA_INST (0x43, RRE, LCXBR), - DA_INST (0x44, RRE, LEDBR), - DA_INST (0x45, RRE, LDXBR), - DA_INST (0x46, RRE, LEXBR), - DA_INST (0x47, RRF2, FIXBR), - DA_INST (0x48, RRE, KXBR), - DA_INST (0x49, RRE, CXBR), - DA_INST (0x4A, RRE, AXBR), - DA_INST (0x4B, RRE, SXBR), - DA_INST (0x4C, RRE, MXBR), - DA_INST (0x4D, RRE, DXBR), - DA_INST (0x50, RRF2, TBEDR), - DA_INST (0x51, RRF2, TBDR), - DA_INST (0x53, RRF3, DIEBR), - DA_INST (0x57, RRF2, FIEBR), - DA_INST (0x58, RRE, THDER), - DA_INST (0x59, RRE, THDR), - DA_INST (0x5B, RRF3, DIDBR), - DA_INST (0x5F, RRF2, FIDBR), - DA_INST (0x60, RRE, LPXR), - DA_INST (0x61, RRE, LNXR), - DA_INST (0x62, RRE, LTXR), - DA_INST (0x63, RRE, LCXR), - DA_INST (0x65, RRE, LXR), - DA_INST (0x66, RRE, LEXR), - DA_INST (0x67, RRE, FIXR), - DA_INST (0x69, RRE, CXR), - DA_INST (0x70, RRE, LPDFR), - DA_INST (0x71, RRE, LNDFR), - DA_INST (0x72, RRF1, CPSDR), - DA_INST (0x73, RRE, LCDFR), - DA_INST (0x74, RRE, LZER), - DA_INST (0x75, RRE, LZDR), - DA_INST (0x76, RRE, LZXR), - DA_INST (0x77, RRE, FIER), - DA_INST (0x7F, RRE, FIDR), - DA_INST (0x84, RRE, SFPC), - DA_INST (0x85, RRE, SFASR), - DA_INST (0x8C, RRE, EFPC), - DA_INST (0x94, RRE, CEFBR), - DA_INST (0x95, RRE, CDFBR), - DA_INST (0x96, RRE, CXFBR), - DA_INST (0x98, RRF2, CFEBR), - DA_INST (0x99, RRF2, CFDBR), - DA_INST (0x9A, RRF2, CFXBR), - DA_INST (0xA4, RRE, CEGBR), - DA_INST (0xA5, RRE, CDGBR), - DA_INST (0xA6, RRE, CXGBR), - DA_INST (0xA8, RRF2, CGEBR), - DA_INST (0xA9, RRF2, CGDBR), - DA_INST (0xAA, RRF2, CGXBR), - DA_INST (0xB4, RRE, CEFR), - DA_INST (0xB5, RRE, CDFR), - DA_INST (0xB6, RRE, CXFR), - DA_INST (0xB8, RRF2, CFER), - DA_INST (0xB9, RRF2, CFDR), - DA_INST (0xBA, RRF2, CFXR), - DA_INST (0xC1, RRE, LDGR), - DA_INST (0xC4, RRE, CEGR), - DA_INST (0xC5, RRE, CDGR), - DA_INST (0xC6, RRE, CXGR), - DA_INST (0xC8, RRF2, CGER), - DA_INST (0xC9, RRF2, CGDR), - DA_INST (0xCA, RRF2, CGXR), - DA_INST (0xCD, RRE, LGDR), - DA_INST (0xD0, RRR, MDTR), - DA_INST (0xD1, RRR, DDTR), - DA_INST (0xD2, RRR, ADTR), - DA_INST (0xD3, RRR, SDTR), - DA_INST (0xD4, RRF3, LDETR), - DA_INST (0xD5, RRF3, LEDTR), - DA_INST (0xD6, RRE, LTDTR), - DA_INST (0xD7, RRF3, FIDTR), - DA_INST (0xD8, RRR, MXTR), - DA_INST (0xD9, RRR, DXTR), - DA_INST (0xDA, RRR, AXTR), - DA_INST (0xDB, RRR, SXTR), - DA_INST (0xDC, RRF3, LXDTR), - DA_INST (0xDD, RRF3, LDXTR), - DA_INST (0xDE, RRE, LTXTR), - DA_INST (0xDF, RRF3, FIXTR), - DA_INST (0xE0, RRE, KDTR), - DA_INST (0xE1, RRF2, CGDTR), - DA_INST (0xE2, RRE, CUDTR), - DA_INST (0xE3, RRF3, CSDTR), - DA_INST (0xE4, RRE, CDTR), - DA_INST (0xE5, RRE, EEDTR), - DA_INST (0xE7, RRE, ESDTR), - DA_INST (0xE8, RRE, KXTR), - DA_INST (0xE9, RRF2, CGXTR), - DA_INST (0xEA, RRE, CUXTR), - DA_INST (0xEB, RRF3, CSXTR), - DA_INST (0xEC, RRE, CXTR), - DA_INST (0xED, RRE, EEXTR), - DA_INST (0xEF, RRE, ESXTR), - DA_INST (0xF1, RRE, CDGTR), - DA_INST (0xF2, RRE, CDUTR), - DA_INST (0xF3, RRE, CDSTR), - DA_INST (0xF4, RRE, CEDTR), - DA_INST (0xF5, RRF3, QADTR), - DA_INST (0xF6, RRF3, IEDTR), - DA_INST (0xF7, RRF3, RRDTR), - DA_INST (0xF9, RRE, CXGTR), - DA_INST (0xFA, RRE, CXUTR), - DA_INST (0xFB, RRE, CXSTR), - DA_INST (0xFC, RRE, CEXTR), - DA_INST (0xFD, RRF3, QAXTR), - DA_INST (0xFE, RRF3, IEXTR), - DA_INST (0xFF, RRF3, RRXTR), -}; - -static struct disassm_instruction l2_b9[256] = { /* B9xx */ - DA_INST (0x00, RRE, LPGR), - DA_INST (0x01, RRE, LNGR), - DA_INST (0x02, RRE, LTGR), - DA_INST (0x03, RRE, LCGR), - DA_INST (0x04, RRE, LGR), - DA_INST (0x05, RRE, LURAG), - DA_INST (0x06, RRE, LGBR), - DA_INST (0x07, RRE, LGHR), - DA_INST (0x08, RRE, AGR), - DA_INST (0x09, RRE, SGR), - DA_INST (0x0A, RRE, ALGR), - DA_INST (0x0B, RRE, SLGR), - DA_INST (0x0C, RRE, MSGR), - DA_INST (0x0D, RRE, DSGR), - DA_INST (0x0E, RRE, EREGG), - DA_INST (0x0F, RRE, LRVGR), - DA_INST (0x10, RRE, LPGFR), - DA_INST (0x11, RRE, LNGFR), - DA_INST (0x12, RRE, LTGFR), - DA_INST (0x13, RRE, LCGFR), - DA_INST (0x14, RRE, LGFR), - DA_INST (0x16, RRE, LLGFR), - DA_INST (0x17, RRE, LLGTR), - DA_INST (0x18, RRE, AGFR), - DA_INST (0x19, RRE, SGFR), - DA_INST (0x1A, RRE, ALGFR), - DA_INST (0x1B, RRE, SLGFR), - DA_INST (0x1C, RRE, MSGFR), - DA_INST (0x1D, RRE, DSGFR), - DA_INST (0x1E, RRE, KMAC), - DA_INST (0x1F, RRE, LRVR), - DA_INST (0x20, RRE, CGR), - DA_INST (0x21, RRE, CLGR), - DA_INST (0x25, RRE, STURG), - DA_INST (0x26, RRE, LBR), - DA_INST (0x27, RRE, LHR), - DA_INST (0x2E, RRE, KM), - DA_INST (0x2F, RRE, KMC), - DA_INST (0x30, RRE, CGFR), - DA_INST (0x31, RRE, CLGFR), - DA_INST (0x3E, RRE, KIMD), - DA_INST (0x3F, RRE, KLMD), - DA_INST (0x46, RRE, BCTGR), - DA_INST (0x60, RRF2, CGRT), - DA_INST (0x61, RRF2, CLGRT), - DA_INST (0x72, RRF2, CRT), - DA_INST (0x73, RRF2, CLRT), - DA_INST (0x80, RRE, NGR), - DA_INST (0x81, RRE, OGR), - DA_INST (0x82, RRE, XGR), - DA_INST (0x83, RRE, FLOGR), - DA_INST (0x84, RRE, LLGCR), - DA_INST (0x85, RRE, LLGHR), - DA_INST (0x86, RRE, MLGR), - DA_INST (0x87, RRE, DLGR), - DA_INST (0x88, RRE, ALCGR), - DA_INST (0x89, RRE, SLBGR), - DA_INST (0x8A, RRE, CSPG), - DA_INST (0x8D, RRE, EPSW), - DA_INST (0x8E, RRF3, IDTE), - DA_INST (0x90, RRF2, TRTT), - DA_INST (0x91, RRF2, TRTO), - DA_INST (0x92, RRF2, TROT), - DA_INST (0x93, RRF2, TROO), - DA_INST (0x94, RRE, LLCR), - DA_INST (0x95, RRE, LLHR), - DA_INST (0x96, RRE, MLR), - DA_INST (0x97, RRE, DLR), - DA_INST (0x98, RRE, ALCR), - DA_INST (0x99, RRE, SLBR), - DA_INST (0x9A, RRE, EPAIR), - DA_INST (0x9B, RRE, ESAIR), - DA_INST (0x9D, RRE, ESEA), - DA_INST (0x9E, RRE, PTI), - DA_INST (0x9F, RRE, SSAIR), - DA_INST (0xA2, RRE, PTF), - DA_INST (0xAA, RRF3, LPTEA), - DA_INST (0xAF, RRE, PFMF), - DA_INST (0xB0, RRF2, CU14), - DA_INST (0xB1, RRF2, CU24), - DA_INST (0xB2, RRE, CU41), - DA_INST (0xB3, RRE, CU42), - DA_INST (0xBD, RRF2, TRTRE), - DA_INST (0xBE, RRE, SRSTU), - DA_INST (0xBF, RRF2, TRTE), -}; - -static struct disassm_instruction l2_c0[16] = { /* C0x */ - DA_INST (0x0, RIL1, LARL), - DA_INST (0x1, RIL1, LGFI), - DA_INST (0x4, RIL2, BRCL), - DA_INST (0x5, RIL1, BRASL), - DA_INST (0x6, RIL1, XIHF), - DA_INST (0x7, RIL1, XILF), - DA_INST (0x8, RIL1, IIHF), - DA_INST (0x9, RIL1, IILF), - DA_INST (0xA, RIL1, NIHF), - DA_INST (0xB, RIL1, NILF), - DA_INST (0xC, RIL1, OIHF), - DA_INST (0xD, RIL1, OILF), - DA_INST (0xE, RIL1, LLIHF), - DA_INST (0xF, RIL1, LLILF), -}; - -static struct disassm_instruction l2_c2[16] = { /* C2x */ - DA_INST (0x0, RIL1, MSGFI), - DA_INST (0x1, RIL1, MSFI), - DA_INST (0x4, RIL1, SLGFI), - DA_INST (0x5, RIL1, SLFI), - DA_INST (0x8, RIL1, AGFI), - DA_INST (0x9, RIL1, AFI), - DA_INST (0xA, RIL1, ALGFI), - DA_INST (0xB, RIL1, ALFI), - DA_INST (0xC, RIL1, CGFI), - DA_INST (0xD, RIL1, CFI), - DA_INST (0xE, RIL1, CLGFI), - DA_INST (0xF, RIL1, CLFI), -}; - -static struct disassm_instruction l2_c4[16] = { /* C4x */ - DA_INST (0x2, RIL1, LLHRL), - DA_INST (0x4, RIL1, LGHRL), - DA_INST (0x5, RIL1, LHRL), - DA_INST (0x6, RIL1, LLGHRL), - DA_INST (0x7, RIL1, STHRL), - DA_INST (0x8, RIL1, LGRL), - DA_INST (0xB, RIL1, STGRL), - DA_INST (0xC, RIL1, LGFRL), - DA_INST (0xD, RIL1, LRL), - DA_INST (0xE, RIL1, LLGFRL), - DA_INST (0xF, RIL1, STRL), -}; - -static struct disassm_instruction l2_c6[16] = { /* C6x */ - DA_INST (0x0, RIL1, EXRL), - DA_INST (0x2, RIL2, PFDRL), - DA_INST (0x4, RIL1, CGHRL), - DA_INST (0x5, RIL1, CHRL), - DA_INST (0x6, RIL1, CLGHRL), - DA_INST (0x7, RIL1, CLHRL), - DA_INST (0x8, RIL1, CGRL), - DA_INST (0xA, RIL1, CLGRL), - DA_INST (0xC, RIL1, CGFRL), - DA_INST (0xD, RIL1, CRL), - DA_INST (0xE, RIL1, CLGFRL), - DA_INST (0xF, RIL1, CLRL), -}; - -static struct disassm_instruction l2_c8[16] = { /* C8x */ - DA_INST (0x0, SSF, MVCOS), - DA_INST (0x1, SSF, ECTG), - DA_INST (0x2, SSF, CSST), -}; - -static struct disassm_instruction l2_e3[256] = { /* E3xx */ - DA_INST (0x02, RXY, LTG), - DA_INST (0x03, RXY, LRAG), - DA_INST (0x04, RXY, LG), - DA_INST (0x06, RXY, CVBY), - DA_INST (0x08, RXY, AG), - DA_INST (0x09, RXY, SG), - DA_INST (0x0A, RXY, ALG), - DA_INST (0x0B, RXY, SLG), - DA_INST (0x0C, RXY, MSG), - DA_INST (0x0D, RXY, DSG), - DA_INST (0x0E, RXY, CVBG), - DA_INST (0x0F, RXY, LRVG), - DA_INST (0x12, RXY, LT), - DA_INST (0x13, RXY, LRAY), - DA_INST (0x14, RXY, LGF), - DA_INST (0x15, RXY, LGH), - DA_INST (0x16, RXY, LLGF), - DA_INST (0x17, RXY, LLGT), - DA_INST (0x18, RXY, AGF), - DA_INST (0x19, RXY, SGF), - DA_INST (0x1A, RXY, ALGF), - DA_INST (0x1B, RXY, SLGF), - DA_INST (0x1C, RXY, MSGF), - DA_INST (0x1D, RXY, DSGF), - DA_INST (0x1E, RXY, LRV), - DA_INST (0x1F, RXY, LRVH), - DA_INST (0x20, RXY, CG), - DA_INST (0x21, RXY, CLG), - DA_INST (0x24, RXY, STG), - DA_INST (0x26, RXY, CVDY), - DA_INST (0x2E, RXY, CVDG), - DA_INST (0x2F, RXY, STRVG), - DA_INST (0x30, RXY, CGF), - DA_INST (0x31, RXY, CLGF), - DA_INST (0x32, RXY, LTGF), - DA_INST (0x34, RXY, CGH), - DA_INST (0x36, RXY, PFD), - DA_INST (0x3E, RXY, STRV), - DA_INST (0x3F, RXY, STRVH), - DA_INST (0x46, RXY, BCTG), - DA_INST (0x50, RXY, STY), - DA_INST (0x51, RXY, MSY), - DA_INST (0x54, RXY, NY), - DA_INST (0x55, RXY, CLY), - DA_INST (0x56, RXY, OY), - DA_INST (0x57, RXY, XY), - DA_INST (0x58, RXY, LY), - DA_INST (0x59, RXY, CY), - DA_INST (0x5A, RXY, AY), - DA_INST (0x5B, RXY, SY), - DA_INST (0x5C, RXY, MFY), - DA_INST (0x5E, RXY, ALY), - DA_INST (0x5F, RXY, SLY), - DA_INST (0x70, RXY, STHY), - DA_INST (0x71, RXY, LAY), - DA_INST (0x72, RXY, STCY), - DA_INST (0x73, RXY, ICY), - DA_INST (0x75, RXY, LAEY), - DA_INST (0x76, RXY, LB), - DA_INST (0x77, RXY, LGB), - DA_INST (0x78, RXY, LHY), - DA_INST (0x79, RXY, CHY), - DA_INST (0x7A, RXY, AHY), - DA_INST (0x7B, RXY, SHY), - DA_INST (0x7C, RXY, MHY), - DA_INST (0x80, RXY, NG), - DA_INST (0x81, RXY, OG), - DA_INST (0x82, RXY, XG), - DA_INST (0x86, RXY, MLG), - DA_INST (0x87, RXY, DLG), - DA_INST (0x88, RXY, ALCG), - DA_INST (0x89, RXY, SLBG), - DA_INST (0x8E, RXY, STPQ), - DA_INST (0x8F, RXY, LPQ), - DA_INST (0x90, RXY, LLGC), - DA_INST (0x91, RXY, LLGH), - DA_INST (0x94, RXY, LLC), - DA_INST (0x95, RXY, LLH), - DA_INST (0x96, RXY, ML), - DA_INST (0x97, RXY, DL), - DA_INST (0x98, RXY, ALC), - DA_INST (0x99, RXY, SLB), -}; - -static struct disassm_instruction l2_e5[256] = { /* E5xx */ - DA_INST (0x00, SSE, LASP), - DA_INST (0x01, SSE, TPROT), - DA_INST (0x02, SSE, STRAG), - DA_INST (0x0E, SSE, MVCSK), - DA_INST (0x0F, SSE, MVCDK), - DA_INST (0x44, SIL, MVHHI), - DA_INST (0x48, SIL, MVGHI), - DA_INST (0x4C, SIL, MVHI), - DA_INST (0x54, SIL, CHHSI), - DA_INST (0x55, SIL, CLHHSI), - DA_INST (0x58, SIL, CGHSI), - DA_INST (0x59, SIL, CLGHSI), - DA_INST (0x5C, SIL, CHSI), - DA_INST (0x5D, SIL, CLFHSI), -}; - -static struct disassm_instruction l2_eb[256] = { /* EBxx */ - DA_INST (0x04, RSY1, LMG), - DA_INST (0x0A, RSY1, SRAG), - DA_INST (0x0B, RSY1, SLAG), - DA_INST (0x0C, RSY1, SRLG), - DA_INST (0x0D, RSY1, SLLG), - DA_INST (0x0F, RSY1, TRACG), - DA_INST (0x14, RSY1, CSY), - DA_INST (0x1C, RSY1, RLLG), - DA_INST (0x1D, RSY1, RLL), - DA_INST (0x20, RSY2, CLMH), - DA_INST (0x21, RSY2, CLMY), - DA_INST (0x24, RSY1, STMG), - DA_INST (0x25, RSY1, STCTG), - DA_INST (0x26, RSY1, STMH), - DA_INST (0x2C, RSY2, STCMH), - DA_INST (0x2D, RSY2, STCMY), - DA_INST (0x2F, RSY1, LCTLG), - DA_INST (0x30, RSY1, CSG), - DA_INST (0x31, RSY1, CDSY), - DA_INST (0x3E, RSY1, CDSG), - DA_INST (0x44, RSY1, BXHG), - DA_INST (0x45, RSY1, BXLEG), - DA_INST (0x4C, RSY1, ECAG), - DA_INST (0x51, SIY, TMY), - DA_INST (0x52, SIY, MVIY), - DA_INST (0x54, SIY, NIY), - DA_INST (0x55, SIY, CLIY), - DA_INST (0x56, SIY, OIY), - DA_INST (0x57, SIY, XIY), - DA_INST (0x6A, SIY, ASI), - DA_INST (0x6E, SIY, ALSI), - DA_INST (0x80, RSY2, ICMH), - DA_INST (0x81, RSY2, ICMY), - DA_INST (0x8E, RSY1, MVCLU), - DA_INST (0x8F, RSY1, CLCLU), - DA_INST (0x90, RSY1, STMY), - DA_INST (0x96, RSY1, LMH), - DA_INST (0x98, RSY1, LMY), - DA_INST (0x9A, RSY1, LAMY), - DA_INST (0x9B, RSY1, STAMY), - DA_INST (0xC0, RSL, TP), -}; - -static struct disassm_instruction l2_ec[256] = { /* ECxx */ - DA_INST (0x44, RIE, BRXHG), - DA_INST (0x45, RIE, BRXLG), - DA_INST (0x54, RIE, RNSBG), - DA_INST (0x55, RIE, RISBG), - DA_INST (0x56, RIE, ROSBG), - DA_INST (0x57, RIE, RXSBG), - DA_INST (0x64, RIE, CGRJ), - DA_INST (0x65, RIE, CLGRJ), - DA_INST (0x70, RIE, CGIT), - DA_INST (0x71, RIE, CLGIT), - DA_INST (0x72, RIE, CIT), - DA_INST (0x73, RIE, CLFIT), - DA_INST (0x76, RIE, CRJ), - DA_INST (0x77, RIE, CLRJ), - DA_INST (0x7C, RIE, CGIJ), - DA_INST (0x7D, RIE, CLGIJ), - DA_INST (0x7E, RIE, CIJ), - DA_INST (0x7F, RIE, CLIJ), - DA_INST (0xE4, RRS, CGRB), - DA_INST (0xE5, RRS, CLGRB), - DA_INST (0xF6, RRS, CRB), - DA_INST (0xF7, RRS, CLRB), - DA_INST (0xFC, RIS, CGIB), - DA_INST (0xFD, RIS, CLGIB), -}; - -static struct disassm_instruction l2_ed[256] = { /* EDxx */ - DA_INST (0x04, RXE, LDEB), - DA_INST (0x05, RXE, LXDB), - DA_INST (0x06, RXE, LXEB), - DA_INST (0x07, RXE, MXDB), - DA_INST (0x08, RXE, KEB), - DA_INST (0x09, RXE, CEB), - DA_INST (0x0A, RXE, AEB), - DA_INST (0x0B, RXE, SEB), - DA_INST (0x0C, RXE, MDEB), - DA_INST (0x0D, RXE, DEB), - DA_INST (0x0E, RXE, MAEB), - DA_INST (0x0F, RXE, MSEB), - DA_INST (0x10, RXE, TCEB), - DA_INST (0x11, RXE, TCDB), - DA_INST (0x12, RXE, TCXB), - DA_INST (0x14, RXE, SQEB), - DA_INST (0x15, RXE, SQDB), - DA_INST (0x17, RXE, MEEB), - DA_INST (0x18, RXE, KDB), - DA_INST (0x19, RXE, CDB), - DA_INST (0x1A, RXE, ADB), - DA_INST (0x1B, RXE, SDB), - DA_INST (0x1C, RXE, MDB), - DA_INST (0x1D, RXE, DDB), - DA_INST (0x1E, RXF, MADB), - DA_INST (0x1F, RXF, MSDB), - DA_INST (0x24, RXE, LDE), - DA_INST (0x25, RXE, LXD), - DA_INST (0x26, RXE, LXE), - DA_INST (0x2E, RXF, MAE), - DA_INST (0x2F, RXF, MSE), - DA_INST (0x34, RXE, SQE), - DA_INST (0x35, RXE, SQD), - DA_INST (0x37, RXE, MEE), - DA_INST (0x38, RXF, MAYL), - DA_INST (0x39, RXF, MYL), - DA_INST (0x3A, RXF, MAY), - DA_INST (0x3B, RXF, MY), - DA_INST (0x3C, RXF, MAYH), - DA_INST (0x3D, RXF, MYH), - DA_INST (0x3E, RXF, MAD), - DA_INST (0x3F, RXF, MSD), - DA_INST (0x40, RXF, SLDT), - DA_INST (0x41, RXF, SRDT), - DA_INST (0x48, RXF, SLXT), - DA_INST (0x49, RXF, SRXT), - DA_INST (0x50, RXE, TDCET), - DA_INST (0x51, RXE, TDGET), - DA_INST (0x54, RXE, TDCDT), - DA_INST (0x55, RXE, TDGDT), - DA_INST (0x58, RXE, TDCXT), - DA_INST (0x59, RXE, TDGXT), - DA_INST (0x64, RXY, LEY), - DA_INST (0x65, RXY, LDY), - DA_INST (0x66, RXY, STEY), - DA_INST (0x67, RXY, STDY), -}; - -static struct disassm_instruction l1[256] = { /* xx */ - DA_INST_TBL (0x01, l2_01, 8, 8), - DA_INST (0x04, RR, SPM), - DA_INST (0x05, RR, BALR), - DA_INST (0x06, RR, BCTR), - DA_INST (0x07, RR_MASK, BCR), - DA_INST (0x0A, I, SVC), - DA_INST (0x0B, RR, BSM), - DA_INST (0x0C, RR, BASSM), - DA_INST (0x0D, RR, BASR), - DA_INST (0x0E, RR, MVCL), - DA_INST (0x0F, RR, CLCL), - DA_INST (0x10, RR, LPR), - DA_INST (0x11, RR, LNR), - DA_INST (0x12, RR, LTR), - DA_INST (0x13, RR, LCR), - DA_INST (0x14, RR, NR), - DA_INST (0x15, RR, CLR), - DA_INST (0x16, RR, OR), - DA_INST (0x17, RR, XR), - DA_INST (0x18, RR, LR), - DA_INST (0x19, RR, CR), - DA_INST (0x1A, RR, AR), - DA_INST (0x1B, RR, SR), - DA_INST (0x1C, RR, MR), - DA_INST (0x1D, RR, DR), - DA_INST (0x1E, RR, ALR), - DA_INST (0x1F, RR, SLR), - DA_INST (0x20, RR, LPDR), - DA_INST (0x21, RR, LNDR), - DA_INST (0x22, RR, LTDR), - DA_INST (0x23, RR, LCDR), - DA_INST (0x24, RR, HDR), - DA_INST (0x25, RR, LDXR), - DA_INST (0x26, RR, MXR), - DA_INST (0x27, RR, MXDR), - DA_INST (0x28, RR, LDR), - DA_INST (0x29, RR, CDR), - DA_INST (0x2A, RR, ADR), - DA_INST (0x2B, RR, SDR), - DA_INST (0x2C, RR, MDR), - DA_INST (0x2D, RR, DDR), - DA_INST (0x2E, RR, AWR), - DA_INST (0x2F, RR, SWR), - DA_INST (0x30, RR, LPER), - DA_INST (0x31, RR, LNER), - DA_INST (0x32, RR, LTER), - DA_INST (0x33, RR, LCER), - DA_INST (0x34, RR, HER), - DA_INST (0x35, RR, LEDR), - DA_INST (0x36, RR, AXR), - DA_INST (0x37, RR, SXR), - DA_INST (0x38, RR, LER), - DA_INST (0x39, RR, CER), - DA_INST (0x3A, RR, AER), - DA_INST (0x3B, RR, SER), - DA_INST (0x3C, RR, MDER), - DA_INST (0x3D, RR, DER), - DA_INST (0x3E, RR, AUR), - DA_INST (0x3F, RR, SUR), - DA_INST (0x40, RX, STH), - DA_INST (0x41, RX, LA), - DA_INST (0x42, RX, STC), - DA_INST (0x43, RX, IC), - DA_INST (0x44, RX, EX), - DA_INST (0x45, RX, BAL), - DA_INST (0x46, RX, BCT), - DA_INST (0x47, RX_MASK, BC), - DA_INST (0x48, RX, LH), - DA_INST (0x49, RX, CH), - DA_INST (0x4A, RX, AH), - DA_INST (0x4B, RX, SH), - DA_INST (0x4C, RX, MH), - DA_INST (0x4D, RX, BAS), - DA_INST (0x4E, RX, CVD), - DA_INST (0x4F, RX, CVB), - DA_INST (0x50, RX, ST), - DA_INST (0x51, RX, LAE), - DA_INST (0x54, RX, N), - DA_INST (0x55, RX, CL), - DA_INST (0x56, RX, O), - DA_INST (0x57, RX, X), - DA_INST (0x58, RX, L), - DA_INST (0x59, RX, C), - DA_INST (0x5A, RX, A), - DA_INST (0x5B, RX, S), - DA_INST (0x5C, RX, M), - DA_INST (0x5D, RX, D), - DA_INST (0x5E, RX, AL), - DA_INST (0x5F, RX, SL), - DA_INST (0x60, RX, STD), - DA_INST (0x67, RX, MXD), - DA_INST (0x68, RX, LD), - DA_INST (0x69, RX, CD), - DA_INST (0x6A, RX, AD), - DA_INST (0x6B, RX, SD), - DA_INST (0x6C, RX, MD), - DA_INST (0x6D, RX, DD), - DA_INST (0x6E, RX, AW), - DA_INST (0x6F, RX, SW), - DA_INST (0x70, RX, STE), - DA_INST (0x71, RX, MS), - DA_INST (0x78, RX, LE), - DA_INST (0x79, RX, CE), - DA_INST (0x7A, RX, AE), - DA_INST (0x7B, RX, SE), - DA_INST (0x7C, RX, MDE), - DA_INST (0x7D, RX, DE), - DA_INST (0x7E, RX, AU), - DA_INST (0x7F, RX, SU), - DA_INST (0x80, S, SSM), - DA_INST (0x82, S, LPSW), - DA_INST (0x83, DIAG, DIAG), - DA_INST (0x84, RSI, BRXH), - DA_INST (0x85, RSI, BRXLE), - DA_INST (0x86, RS1, BXH), - DA_INST (0x87, RS1, BXLE), - DA_INST (0x88, RS1, SRL), - DA_INST (0x89, RS1, SLL), - DA_INST (0x8A, RS1, SRA), - DA_INST (0x8B, RS1, SLA), - DA_INST (0x8C, RS1, SRDL), - DA_INST (0x8D, RS1, SLDL), - DA_INST (0x8E, RS1, SRDA), - DA_INST (0x8F, RS1, SLDA), - DA_INST (0x90, RS1, STM), - DA_INST (0x91, SI, TM), - DA_INST (0x92, SI, MVI), - DA_INST (0x93, S, TS), - DA_INST (0x94, SI, NI), - DA_INST (0x95, SI, CLI), - DA_INST (0x96, SI, OI), - DA_INST (0x97, SI, XI), - DA_INST (0x98, RS1, LM), - DA_INST (0x99, RS1, TRACE), - DA_INST (0x9A, RS1, LAM), - DA_INST (0x9B, RS1, STAM), - DA_INST_TBL (0xA5, l2_a5, 4, 12), - DA_INST_TBL (0xA7, l2_a7, 4, 12), - DA_INST (0xA8, RS1, MVCLE), - DA_INST (0xA9, RS1, CLCLE), - DA_INST (0xAC, SI, STNSM), - DA_INST (0xAD, SI, STOSM), - DA_INST (0xAE, RS1, SIGP), - DA_INST (0xAF, SI, MC), - DA_INST (0xB1, RX, LRA), - DA_INST_TBL (0xB2, l2_b2, 8, 8), - DA_INST_TBL (0xB3, l2_b3, 8, 8), - DA_INST (0xB6, RS1, STCTL), - DA_INST (0xB7, RS1, LCTL), - DA_INST_TBL (0xB9, l2_b9, 8, 8), - DA_INST (0xBA, RS1, CS), - DA_INST (0xBB, RS1, CDS), - DA_INST (0xBD, RS2, CLM), - DA_INST (0xBE, RS2, STCM), - DA_INST (0xBF, RS2, ICM), - DA_INST_TBL (0xC0, l2_c0, 4, 12), - DA_INST_TBL (0xC2, l2_c2, 4, 12), - DA_INST_TBL (0xC4, l2_c4, 4, 12), - DA_INST_TBL (0xC6, l2_c6, 4, 12), - DA_INST_TBL (0xC8, l2_c8, 4, 12), - DA_INST (0xD0, SS1, TRTR), - DA_INST (0xD1, SS1, MVN), - DA_INST (0xD2, SS1, MVC), - DA_INST (0xD3, SS1, MVZ), - DA_INST (0xD4, SS1, NC), - DA_INST (0xD5, SS1, CLC), - DA_INST (0xD6, SS1, OC), - DA_INST (0xD7, SS1, XC), - DA_INST (0xD9, SS4, MVCK), - DA_INST (0xDA, SS4, MVCP), - DA_INST (0xDB, SS4, MVCS), - DA_INST (0xDC, SS1, TR), - DA_INST (0xDD, SS1, TRT), - DA_INST (0xDE, SS1, ED), - DA_INST (0xDF, SS1, EDMK), - DA_INST (0xE1, SS1, PKU), - DA_INST (0xE2, SS1, UNPKU), - DA_INST_TBL (0xE3, l2_e3, 8, 40), - DA_INST_TBL (0xE5, l2_e5, 8, 8), - DA_INST (0xE8, SS1, MVCIN), - DA_INST (0xE9, SS1, PKA), - DA_INST (0xEA, SS1, UNPKA), - DA_INST_TBL (0xEB, l2_eb, 8, 40), - DA_INST_TBL (0xEC, l2_ec, 8, 40), - DA_INST_TBL (0xED, l2_ed, 8, 40), - DA_INST (0xEE, SS5, PLO), - DA_INST (0xEF, SS5, LMD), - DA_INST (0xF0, SS3, SRP), - DA_INST (0xF1, SS2, MVO), - DA_INST (0xF2, SS2, PACK), - DA_INST (0xF3, SS2, UNPK), - DA_INST (0xF8, SS2, ZAP), - DA_INST (0xF9, SS2, CP), - DA_INST (0xFA, SS2, AP), - DA_INST (0xFB, SS2, SP), - DA_INST (0xFC, SS2, MP), - DA_INST (0xFD, SS2, DP), -}; - -static int da_snprintf(u8 *bytes, char *buf, int buflen, u8 opcode, struct - disassm_instruction *table) -{ -#define IPFX "%-6s " - - int ilc = opcode >> 6; - struct disassm_instruction *inst = &table[opcode]; - - switch (inst->fmt) { - case IF_INV: - snprintf(buf, buflen, "??"); - break; - case IF_VAR: - { - unsigned char subop; /* sub op-code */ - - /* get the right byte */ - subop = *(bytes+(inst->loc/8)); - - /* shift the needed portion right */ - subop >>= 8 - inst->len - (inst->loc%8); - - /* mask out any unneeded high bits */ - subop &= (1 << inst->len) - 1; - - snprintf(buf, buflen, "??? (many, X'%02X'+ " - "X'%02X', table = %p)", opcode, subop, - inst->u.ptr); - if (inst->u.ptr) - da_snprintf(bytes, buf, buflen, subop, inst->u.ptr); - break; - } - case IF_DIAG: - snprintf(buf, buflen, IPFX "X'%06X'", - inst->u.name, - *((u32*)(bytes)) & 0xffffff); /* I */ - break; - case IF_E: - snprintf(buf, buflen, IPFX, - inst->u.name); - break; - case IF_I: - snprintf(buf, buflen, IPFX "X'%02X'", - inst->u.name, - *(bytes+1)); /* I */ - break; - case IF_RI1: - case IF_RI2: - snprintf(buf, buflen, IPFX "%s%d,%d", - inst->u.name, - (inst->fmt == IF_RI1 ? "R" : ""), /* reg/mask */ - bytes[1] >> 4, /* R1/M1 */ - *((u16*)(bytes+2))); /* I2 */ - break; - case IF_RIL1: - case IF_RIL2: - snprintf(buf, buflen, IPFX "%s%d,%d", - inst->u.name, - (inst->fmt == IF_RIL1 ? "R" : ""), /* reg/mask */ - bytes[1] >> 4, /* R1/M1 */ - *((u32*)(bytes+2))); /* I2 */ - break; - case IF_RR: - case IF_RR_MASK: - snprintf(buf, buflen, IPFX "%s%d,R%d", - inst->u.name, - inst->fmt == IF_RR_MASK ? "" : "R", - bytes[1] >> 4, /* R1 */ - bytes[1] & 0xf); /* R2 */ - break; - case IF_RRE: - snprintf(buf, buflen, IPFX "R%d,R%d", - inst->u.name, - bytes[3] >> 4, /* R1 */ - bytes[3] & 0xf); /* R2 */ - break; - case IF_RS1: - case IF_RS2: - snprintf(buf, buflen, IPFX "R%d,%s%d,%d(R%d)", - inst->u.name, - bytes[1] >> 4, /* R1 */ - (inst->fmt == IF_RS1 ? "R" : ""), /* reg/mask */ - bytes[1] & 0xf, /* R3/M3 */ - *((u16*)(bytes+2)) & 0x0fff, /* D2 */ - bytes[2] >> 4); /* B2 */ - break; - case IF_RSI: - snprintf(buf, buflen, IPFX "R%d,R%d,%d", - inst->u.name, - bytes[1] >> 4, /* R1 */ - bytes[1] & 0xf, /* R3 */ - *((u16*)(bytes+2))); /* I2 */ - break; - case IF_RSY1: - case IF_RSY2: - snprintf(buf, buflen, IPFX "R%d,%s%d,%d(R%d)", - inst->u.name, - bytes[1] >> 4, /* R1 */ - (inst->fmt == IF_RSY1 ? "R" : ""), /* reg/mask */ - bytes[1] & 0xf, /* R3/M3 */ - ((u32)*((u16*)(bytes+2)) & 0x0fff) + - (((u32)*(bytes+4)) << 12), /* D2 */ - bytes[2] >> 4); /* B2 */ - break; - case IF_RX: - case IF_RX_MASK: - snprintf(buf, buflen, IPFX "%s%d,%d(R%d,R%d)", - inst->u.name, - inst->fmt == IF_RX_MASK ? "" : "R", - bytes[1] >> 4, /* R1 */ - *((u16*)(bytes+2)) & 0x0fff, /* D2 */ - bytes[1] & 0xf, /* X2 */ - bytes[2] >> 4); /* B2 */ - break; - case IF_RXY: - snprintf(buf, buflen, IPFX "R%d,%d(R%d,R%d)", - inst->u.name, - bytes[1] >> 4, /* R1 */ - ((u32)*((u16*)(bytes+2)) & 0x0fff) + - (((u32)*(bytes+4)) << 12), /* D2 */ - bytes[1] & 0xf, /* X2 */ - bytes[2] >> 4); /* B2 */ - break; - case IF_S: - snprintf(buf, buflen, IPFX "%d(R%d)", - inst->u.name, - *((u16*)(bytes+2)) & 0x0fff, /* D2 */ - bytes[2] >> 4); /* B2 */ - break; - case IF_SI: - snprintf(buf, buflen, IPFX "%d(R%d),%d", - inst->u.name, - *((u16*)(bytes+2)) & 0x0fff, /* D1 */ - bytes[2] >> 4, /* B1 */ - bytes[1]); /* I2 */ - break; - case IF_SS1: - snprintf(buf, buflen, IPFX "%d(%d,R%d),%d(R%d)", - inst->u.name, - *((u16*)(bytes+2)) & 0x0fff, /* D1 */ - bytes[1]+1, /* L */ - bytes[2] >> 4, /* B1 */ - *((u16*)(bytes+4)) & 0x0fff, /* D2 */ - bytes[4] >> 4); /* B2 */ - break; - case IF_SS2: - snprintf(buf, buflen, IPFX "%d(%d,R%d),%d(%d,R%d)", - inst->u.name, - *((u16*)(bytes+2)) & 0x0fff, /* D1 */ - (bytes[1] >> 4) + 1, /* L1 */ - bytes[2] >> 4, /* B1 */ - *((u16*)(bytes+4)) & 0x0fff, /* D2 */ - (bytes[1] & 0xf) + 1, /* L2 */ - bytes[4] >> 4); /* B2 */ - break; - case IF_SS3: - snprintf(buf, buflen, IPFX "%d(%d,R%d),%d(R%d),%d", - inst->u.name, - *((u16*)(bytes+2)) & 0x0fff, /* D1 */ - (bytes[1] >> 4) + 1, /* L1 */ - bytes[2] >> 4, /* B1 */ - *((u16*)(bytes+4)) & 0x0fff, /* D2 */ - bytes[4] >> 4, /* B2 */ - bytes[1] & 0xf); /* I3 */ - break; - case IF_SS4: - snprintf(buf, buflen, IPFX "%d(%d,R%d),%d(R%d),R%d", - inst->u.name, - *((u16*)(bytes+2)) & 0x0fff, /* D1 */ - (bytes[1] >> 4) + 1, /* L1 */ - bytes[2] >> 4, /* B1 */ - *((u16*)(bytes+4)) & 0x0fff, /* D2 */ - bytes[4] >> 4, /* B2 */ - bytes[1] & 0xf); /* R3 */ - break; - case IF_SS5: - snprintf(buf, buflen, IPFX "R%d,R%d,%d(R%d),%d(R%d)", - inst->u.name, - bytes[1] >> 4, /* R1 */ - bytes[1] & 0xf, /* R3 */ - *((u16*)(bytes+2)) & 0x0fff, /* D2 */ - bytes[2] >> 4, /* B2 */ - *((u16*)(bytes+4)) & 0x0fff, /* D4 */ - bytes[4] >> 4); /* B4 */ - break; - default: - snprintf(buf, buflen, "%s ???", inst->u.name); - break; - } - - /* return instruction length in bytes */ - return 2 * (ilc >= 2 ? ilc : ilc + 1); -} - -int disassm(u8 *bytes, char *buf, int buflen) -{ - return da_snprintf(bytes, buf, buflen, *bytes, l1); -}
--- a/sys/cp/exception.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -#include <sched.h> -#include <vcpu.h> - -void queue_prog_exception(struct virt_sys *sys, enum PROG_EXCEPTION type, u64 param) -{ - con_printf(sys->con, "FIXME: supposed to inject a %d program exception\n", type); - sys->task->cpu->state = GUEST_STOPPED; -} -
--- a/sys/cp/guest.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -#include <directory.h> -#include <sched.h> -#include <dat.h> -#include <cp.h> - -/* - * FIXME: - * - issue any pending interruptions - */ -void run_guest(struct virt_sys *sys) -{ - u64 save_gpr[16]; - - /* - * FIXME: need to ->icptcode = 0; - */ - - /* - * FIXME: load FPRs & FPCR - */ - - /* - * IMPORTANT: We MUST keep a valid stack address in R15. This way, - * if SIE gets interrupted via an interrupt in the host, the - * scheduler can still get to the struct task pointer on the stack - */ - asm volatile( - /* save current regs */ - " stmg 0,15,%0\n" - /* load the address of the guest state save area */ - " lr 14,%1\n" - /* load the address of the reg save area */ - " la 15,%0\n" - /* load guest's R0-R13 */ - " lmg 0,13,%2(14)\n" - /* SIE */ - " sie %3(14)\n" - /* save guest's R0-R13 */ - " stmg 0,13,%2(14)\n" - /* restore all regs */ - " lmg 0,15,0(15)\n" - - : /* output */ - "+m" (save_gpr) - : /* input */ - "a" (sys->task->cpu), - "J" (offsetof(struct virt_cpu, regs.gpr)), - "J" (offsetof(struct virt_cpu, sie_cb)) - : /* clobbered */ - "memory" - ); - - /* - * FIXME: store FPRs & FPCR - */ - - handle_interception(sys); -}
--- a/sys/cp/guest_ipl.S Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ - # - # We are guaranteed the following: - # - # 1) we are located above 16M - # 2) we are located below 2G - # 3) we are running in ESA/390 - # 4) we are in 31-bit addressing mode - # 5) the guest registers are saved at GUEST_IPL_REGSAVE - # 6) R1 contains the subchannel # - # 7) R2 contains the device # - # 8) R12 contains the base address - # - # Register usage: - # - # R1 = subchannel number - # R2 = device number - # R3 = temp - # R12 = base for this code - # - - # Nice register names -.equ r0,0 -.equ r1,1 -.equ r2,2 -.equ r3,3 -.equ r12,12 -.equ r15,15 - - # new IO interruption PSW address -.equ PSANEWIO,120 - -############################################################################### -# Code begins here # -############################################################################### - -.globl GUEST_IPL_CODE - .type GUEST_IPL_CODE, @function -GUEST_IPL_CODE: - STSCH SCHIB(r12) # get the SCHIB - BNZ ERROR(r12) - - OI SCHIB+5(r12),0x80 # enable the subchannel - - MSCH SCHIB(r12) # load up the SCHIB - BNZ ERROR(r12) - - # got a functioning subchannel, let's set up the new IO psw - - MVC PSANEWIO(8,r0),IOPSW(r12) - - L r3,PSANEWIO+4(r0,r0) - LA r3,IO(r3,r12) # calculate the address of - ST r3,PSANEWIO+4(r0,r0) # the IO handler - - # let's set up a CCW + an ORB, start the IO, and wait - - MVC 0(8,r0),INITCCW(r12) # set up the initial CCW - OI ORB+6(r12),0xff # set the LPM in the ORB - - SSCH ORB(r12) # start the IO - BNZ ERROR(r12) - - LPSW ENABLEDWAIT(r12) # wait for IO interruptions - -.equ IO,(.-GUEST_IPL_CODE) - # this is the IO interrupt handler - - B DONE(r12) - -.equ ERROR,(.-GUEST_IPL_CODE) - # an error occured, return an error - - LM r0,r15,REGSAVE(r12) - DIAG r0,r0,1 # return to hypervisor - -.equ DONE,(.-GUEST_IPL_CODE) - # we were successful! - - LM r0,r15,REGSAVE(r12) - DIAG r0,r0,0 # return to hypervisor - -############################################################################### -# Data begins here # -############################################################################### - -.equ DISABLEDWAIT,(.-GUEST_IPL_CODE) - .long 0x000c0000 - .long 0x80000000 # disabled wait PSW; signal - # return to hypervisor -.equ ENABLEDWAIT,(.-GUEST_IPL_CODE) - .long 0x020c0000 - .long 0x80000000 # enabled wait PSW; wait for IO - -.equ IOPSW,(.-GUEST_IPL_CODE) - .long 0x00080000 - .long 0x80000000 # new IO psw - -.equ INITCCW,(.-GUEST_IPL_CODE) - .long 0x02000000 - .long 0x60000018 # fmt0, read 24 bytes to addr 0 - - .align 4 -.equ ORB,(.-GUEST_IPL_CODE) - .skip (8*4),0 # the ORB is BIG - - .align 4 -.equ SCHIB,(.-GUEST_IPL_CODE) - .skip (13*4),0 # the SCHIB is BIG - - .align 4 -.globl GUEST_IPL_REGSAVE - .type GUEST_IPL_REGSAVE, @function -GUEST_IPL_REGSAVE: -.equ REGSAVE,(.-GUEST_IPL_CODE) # register save area
--- a/sys/cp/init.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,320 +0,0 @@ -#include <directory.h> -#include <sched.h> -#include <errno.h> -#include <page.h> -#include <buddy.h> -#include <slab.h> -#include <dat.h> -#include <cp.h> -#include <clock.h> -#include <ebcdic.h> -#include <vdevice.h> -#include <cpu.h> -#include <mutex.h> -#include <vsprintf.h> - -/* This is used to con_printf to the operator about various async events - - * e.g., user logon - */ -struct console *oper_con; - -static LIST_HEAD(online_users); -static UNLOCKED_MUTEX(online_users_lock); - -static int __alloc_guest_devices(struct virt_sys *sys) -{ - int i; - - INIT_LIST_HEAD(&sys->virt_devs); - - for(i=0; sys->directory->devices[i].type != VDEV_INVAL; i++) { - if (alloc_virt_dev(sys, &sys->directory->devices[i], - 0x10000 + i)) - con_printf(sys->con, "Failed to allocate vdev %04X, SCH = %05X\n", - sys->directory->devices[i].vdev, - 0x10000 + i); - } - - return 0; -} - -static int __alloc_guest_storage(struct virt_sys *sys) -{ - u64 pages = sys->directory->storage_size >> PAGE_SHIFT; - struct page *p; - - INIT_LIST_HEAD(&sys->guest_pages); - - while (pages) { - p = alloc_pages(0, ZONE_NORMAL); - if (!p) - continue; /* FIXME: sleep? */ - - list_add(&p->guest, &sys->guest_pages); - - pages--; - - dat_insert_page(&sys->as, (u64) page_to_addr(p), - pages << PAGE_SHIFT); - } - - return 0; -} - -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_cp_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_cp_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\n", ret); - break; - } -} - -static int cp_init(void *data) -{ - struct virt_sys *sys = data; - struct virt_cpu *cpu; - struct datetime dt; - struct page *page; - - page = alloc_pages(0, ZONE_NORMAL); - BUG_ON(!page); - - cpu = page_to_addr(page); - sys->task->cpu = cpu; - - memset(cpu, 0, PAGE_SIZE); - - __alloc_guest_storage(sys); - __alloc_guest_devices(sys); - - /* - * load guest's address space into the host's PASCE - */ - load_as(&sys->as); - - cpu->cpuid = getcpuid() | 0xFF00000000000000ULL; - - memset(&cpu->sie_cb, 0, sizeof(struct sie_cb)); - cpu->sie_cb.gmsor = 0; - cpu->sie_cb.gmslm = sys->directory->storage_size; - cpu->sie_cb.gbea = 1; - cpu->sie_cb.ecb = 2; - cpu->sie_cb.eca = 0xC1002001U; - /* - * TODO: What about ->scaoh and ->scaol? - */ - - 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(); - } - - 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 cp_con_attn(void *data) -{ - for(;;) { - schedule(); - - for_each_console(__con_attn); - } - - return 0; -} - -void spawn_oper_cp(struct console *con) -{ - struct virt_sys *sys; - - 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("operator"); - BUG_ON(IS_ERR(sys->directory)); - - sys->print_ts = 1; /* print timestamps */ - - sys->task = create_task("OPERATOR-vcpu0", cp_init, sys); - BUG_ON(IS_ERR(sys->task)); - - BUG_ON(IS_ERR(create_task("console-attn", cp_con_attn, NULL))); - - mutex_lock(&online_users_lock); - list_add_tail(&sys->online_users, &online_users); - mutex_unlock(&online_users_lock); -} - -void spawn_user_cp(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, cp_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); -}
--- a/sys/cp/instruction.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -#include <sched.h> -#include <cp.h> - -static const intercept_handler_t instruction_funcs[256] = { - [0xb2] = handle_instruction_priv, /* assorted priv. insts */ -}; - -int handle_instruction(struct virt_sys *sys) -{ - struct virt_cpu *cpu = sys->task->cpu; - intercept_handler_t h; - int err = -EINVAL; - - con_printf(sys->con, "INTRCPT: INST (%04x %08x)\n", - cpu->sie_cb.ipa, - cpu->sie_cb.ipb); - - h = instruction_funcs[cpu->sie_cb.ipa >> 8]; - if (h) - err = h(sys); - - return err; -}
--- a/sys/cp/instruction_priv.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,217 +0,0 @@ -#include <list.h> -#include <sched.h> -#include <cp.h> -#include <vdevice.h> -#include <vcpu.h> - -static int handle_msch(struct virt_sys *sys) -{ - struct virt_cpu *cpu = sys->task->cpu; - - u64 r1 = __guest_gpr(cpu, 1); - u64 addr = RAW_S_1(cpu); - - struct schib *gschib; - struct virt_device *vdev, *vdev_cur; - int ret = 0; - - if ((PAGE_SIZE-(addr & PAGE_MASK)) < sizeof(struct schib)) { - con_printf(sys->con, "The SCHIB crosses page boundary (%016llx; %lu)! CPU stopped\n", - addr, sizeof(struct schib)); - cpu->state = GUEST_STOPPED; - goto out; - } - - /* sch number must be: X'0001____' */ - if ((r1 & 0xffff0000) != 0x00010000) { - queue_prog_exception(sys, PROG_OPERAND, r1); - goto out; - } - - /* schib must be word-aligned */ - if (addr & 0x3) { - queue_prog_exception(sys, PROG_SPEC, addr); - goto out; - } - - /* find the virtual device */ - vdev = NULL; - list_for_each_entry(vdev_cur, &sys->virt_devs, devices) { - if (vdev_cur->sch == (u32) r1) { - vdev = vdev_cur; - break; - } - } - - /* There's no virtual device with this sch number; CC=3 */ - if (!vdev) { - cpu->sie_cb.gpsw.cc = 3; - goto out; - } - - /* translate guest address to host address */ - ret = virt2phy_current(addr, &addr); - if (ret) { - if (ret != -EFAULT) - goto out; - - ret = 0; - queue_prog_exception(sys, PROG_ADDR, addr); - goto out; - } - - gschib = (struct schib*) addr; - - /* - * Condition code 1 is set, and no other action is taken, when the - * subchannel is status pending. (See “Status Control (SC)” on - * page 16-16.) - */ - if (vdev->scsw.sc & SC_STATUS) { - cpu->sie_cb.gpsw.cc = 1; - goto out; - } - - /* - * Condition code 2 is set, and no other action is taken, when a - * clear, halt, or start function is in progress at the - * subchannel. (See “Function Control (FC)” on page 16-12.) - */ - if (vdev->scsw.fc & (FC_START | FC_HALT | FC_CLEAR)) { - cpu->sie_cb.gpsw.cc = 2; - goto out; - } - - /* - * The channel-subsystem operations that may be influenced due to - * placement of SCHIB information in the subchannel are: - * - * • I/O processing (E field) - * • Interruption processing (interruption parameter and ISC field) - * • Path management (D, LPM, and POM fields) - * • Monitoring and address-limit checking (measurement-block index, - * LM, and MM fields) - * • Measurement-block-format control (F field) - * • Extended-measurement-word-mode enable (X field) - * • Concurrent-sense facility (S field) - * • Measurement-block address (MBA) - */ - - if (!gschib->pmcw.v) - goto out_cc0; - - vdev->pmcw.interrupt_param = gschib->pmcw.interrupt_param; - vdev->pmcw.e = gschib->pmcw.e; - vdev->pmcw.isc = gschib->pmcw.isc; - vdev->pmcw.d = gschib->pmcw.d; - vdev->pmcw.lpm = gschib->pmcw.lpm; - vdev->pmcw.pom = gschib->pmcw.pom; - vdev->pmcw.lm = gschib->pmcw.lm; - vdev->pmcw.mm = gschib->pmcw.mm; - vdev->pmcw.f = gschib->pmcw.f; - vdev->pmcw.x = gschib->pmcw.x; - vdev->pmcw.s = gschib->pmcw.s; - vdev->pmcw.mbi = gschib->pmcw.mbi; - /* FIXME: save measurement-block address */ - -out_cc0: - cpu->sie_cb.gpsw.cc = 0; - -out: - return ret; -} - -static int handle_ssch(struct virt_sys *sys) -{ - con_printf(sys->con, "SSCH handler\n"); - return -ENOMEM; -} - -static int handle_stsch(struct virt_sys *sys) -{ - struct virt_cpu *cpu = sys->task->cpu; - - u64 r1 = __guest_gpr(cpu, 1); - u64 addr = RAW_S_1(cpu); - - struct schib *gschib; - struct virt_device *vdev, *vdev_cur; - int ret = 0; - - if ((PAGE_SIZE-(addr & PAGE_MASK)) < sizeof(struct schib)) { - con_printf(sys->con, "The SCHIB crosses page boundary (%016llx; %lu)! CPU stopped\n", - addr, sizeof(struct schib)); - cpu->state = GUEST_STOPPED; - goto out; - } - - /* sch number must be: X'0001____' */ - if ((r1 & 0xffff0000) != 0x00010000) { - queue_prog_exception(sys, PROG_OPERAND, r1); - goto out; - } - - /* schib must be word-aligned */ - if (addr & 0x3) { - queue_prog_exception(sys, PROG_SPEC, addr); - goto out; - } - - /* find the virtual device */ - vdev = NULL; - list_for_each_entry(vdev_cur, &sys->virt_devs, devices) { - if (vdev_cur->sch == (u32) r1) { - vdev = vdev_cur; - break; - } - } - - /* There's no virtual device with this sch number; CC=3 */ - if (!vdev) { - cpu->sie_cb.gpsw.cc = 3; - goto out; - } - - /* translate guest address to host address */ - ret = virt2phy_current(addr, &addr); - if (ret) { - if (ret == -EFAULT) { - ret = 0; - queue_prog_exception(sys, PROG_ADDR, addr); - } - - goto out; - } - - gschib = (struct schib*) addr; - - /* copy! */ - memcpy(&gschib->pmcw, &vdev->pmcw, sizeof(struct pmcw)); - memcpy(&gschib->scsw, &vdev->scsw, sizeof(struct scsw)); - - /* CC: 0 */ - cpu->sie_cb.gpsw.cc = 0; - -out: - return ret; -} - -static const intercept_handler_t instruction_priv_funcs[256] = { - [0x32] = handle_msch, - [0x33] = handle_ssch, - [0x34] = handle_stsch, -}; - -int handle_instruction_priv(struct virt_sys *sys) -{ - struct virt_cpu *cpu = sys->task->cpu; - intercept_handler_t h; - int err = -EINVAL; - - h = instruction_priv_funcs[cpu->sie_cb.ipa & 0xff]; - if (h) - err = h(sys); - - return err; -} -
--- a/sys/cp/intercept.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -#include <directory.h> -#include <sched.h> -#include <dat.h> -#include <cp.h> - -static int handle_noop(struct virt_sys *sys) -{ - return 0; -} - -static int handle_program(struct virt_sys *sys) -{ - con_printf(sys->con, "INTRCPT: PROG\n"); - sys->task->cpu->state = GUEST_STOPPED; - return 0; -} - -static int handle_instruction_and_program(struct virt_sys *sys) -{ - con_printf(sys->con, "INTRCPT: INST+PROG\n"); - sys->task->cpu->state = GUEST_STOPPED; - return 0; -} - -static int handle_ext_req(struct virt_sys *sys) -{ - con_printf(sys->con, "INTRCPT: EXT REQ\n"); - sys->task->cpu->state = GUEST_STOPPED; - return 0; -} - -static int handle_ext_int(struct virt_sys *sys) -{ - con_printf(sys->con, "INTRCPT: EXT INT\n"); - sys->task->cpu->state = GUEST_STOPPED; - return 0; -} - -static int handle_io_req(struct virt_sys *sys) -{ - con_printf(sys->con, "INTRCPT: IO REQ\n"); - sys->task->cpu->state = GUEST_STOPPED; - return 0; -} - -static int handle_wait(struct virt_sys *sys) -{ - con_printf(sys->con, "INTRCPT: WAIT\n"); - sys->task->cpu->state = GUEST_STOPPED; - return 0; -} - -static int handle_validity(struct virt_sys *sys) -{ - con_printf(sys->con, "INTRCPT: VALIDITY\n"); - sys->task->cpu->state = GUEST_STOPPED; - return 0; -} - -static int handle_stop(struct virt_sys *sys) -{ - atomic_clear_mask(CPUSTAT_STOP_INT, &sys->task->cpu->sie_cb.cpuflags); - return 0; -} - -static int handle_oper_except(struct virt_sys *sys) -{ - con_printf(sys->con, "INTRCPT: OPER EXCEPT\n"); - sys->task->cpu->state = GUEST_STOPPED; - return 0; -} - -static int handle_exp_run(struct virt_sys *sys) -{ - con_printf(sys->con, "INTRCPT: EXP RUN\n"); - sys->task->cpu->state = GUEST_STOPPED; - return 0; -} - -static int handle_exp_timer(struct virt_sys *sys) -{ - con_printf(sys->con, "INTRCPT: EXP TIMER\n"); - sys->task->cpu->state = GUEST_STOPPED; - return 0; -} - -static const intercept_handler_t intercept_funcs[0x4c >> 2] = { - [0x00 >> 2] = handle_noop, - [0x04 >> 2] = handle_instruction, - [0x08 >> 2] = handle_program, - [0x0c >> 2] = handle_instruction_and_program, - [0x10 >> 2] = handle_ext_req, - [0x14 >> 2] = handle_ext_int, - [0x18 >> 2] = handle_io_req, - [0x1c >> 2] = handle_wait, - [0x20 >> 2] = handle_validity, - [0x28 >> 2] = handle_stop, - [0x2c >> 2] = handle_oper_except, - [0x44 >> 2] = handle_exp_run, - [0x48 >> 2] = handle_exp_timer, -}; - -void handle_interception(struct virt_sys *sys) -{ - struct virt_cpu *cpu = sys->task->cpu; - intercept_handler_t h; - int err = -EINVAL; - - h = intercept_funcs[cpu->sie_cb.icptcode >> 2]; - if (h) - err = h(sys); - - if (err) { - cpu->state = GUEST_STOPPED; - con_printf(sys->con, "Unknown/mis-handled intercept code %02x, err = %d\n", - cpu->sie_cb.icptcode, err); - } -}
--- a/sys/cp/reset.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,218 +0,0 @@ -#include <directory.h> -#include <sched.h> -#include <dat.h> -#include <cp.h> - -#define RESET_CPU 0x000001 -#define SET_ESA390 0x000002 -#define RESET_PSW 0x000004 -#define RESET_PREFIX 0x000008 -#define RESET_CPU_TIMER 0x000010 -#define RESET_CLK_COMP 0x000020 -#define RESET_TOD_PROG_REG 0x000040 -#define RESET_CR 0x000080 -#define RESET_BREAK_EV_ADDR 0x000100 -#define RESET_FPCR 0x000200 -#define RESET_AR 0x000400 -#define RESET_GPR 0x000800 -#define RESET_FPR 0x001000 -#define RESET_STORAGE_KEYS 0x002000 -#define RESET_STORAGE 0x004000 -#define RESET_NONVOL_STORAGE 0x008000 -#define RESET_EXPANDED_STORAGE 0x010000 -#define RESET_TOD 0x020000 -#define RESET_TOD_STEER 0x040000 -#define RESET_FLOATING_INTERRUPTIONS 0x080000 -#define RESET_IO 0x100000 -#define RESET_PLO_LOCKS 0x200000 -#define __RESET_PLO_LOCKS_PRESERVE 0x400000 -#define RESET_PLO_LOCKS_PRESERVE (RESET_PLO_LOCKS | \ - __RESET_PLO_LOCKS_PRESERVE) - -/* - * These define all the different ways of reseting the system...to save us - * typing later on :) - */ -#define SUBSYSTEM_RESET_FLAGS (RESET_FLOATING_INTERRUPTIONS | RESET_IO) -#define CPU_RESET_FLAGS (RESET_CPU) -#define INIT_CPU_RESET_FLAGS (RESET_CPU | SET_ESA390 | RESET_PSW | \ - RESET_PREFIX | RESET_CPU_TIMER | \ - RESET_CLK_COMP | RESET_TOD_PROG_REG | \ - RESET_CR | RESET_BREAK_EV_ADDR | \ - RESET_FPCR) -#define CLEAR_RESET_FLAGS (RESET_CPU | SET_ESA390 | RESET_PSW | \ - RESET_PREFIX | RESET_CPU_TIMER | \ - RESET_CLK_COMP | RESET_TOD_PROG_REG | \ - RESET_CR | RESET_BREAK_EV_ADDR | RESET_FPCR | \ - RESET_AR | RESET_GPR | RESET_FPR | \ - RESET_STORAGE_KEYS | RESET_STORAGE | \ - RESET_NONVOL_STORAGE | RESET_PLO_LOCKS | \ - RESET_FLOATING_INTERRUPTIONS | RESET_IO) -#define POWER_ON_RESET_FLAGS (RESET_CPU | SET_ESA390 | RESET_PSW | \ - RESET_PREFIX | RESET_CPU_TIMER | \ - RESET_CLK_COMP | RESET_TOD_PROG_REG | \ - RESET_CR | RESET_BREAK_EV_ADDR | RESET_FPCR | \ - RESET_AR | RESET_GPR | RESET_FPR | \ - RESET_STORAGE_KEYS | RESET_STORAGE | \ - RESET_EXPANDED_STORAGE | RESET_TOD | \ - RESET_TOD_STEER | RESET_PLO_LOCKS_PRESERVE | \ - RESET_FLOATING_INTERRUPTIONS | RESET_IO) - -/* - * Reset TODO: - * - handle Captured-z/Architecture-PSW register - */ -static void __perform_cpu_reset(struct virt_sys *sys, int flags) -{ - struct virt_cpu *cpu = sys->task->cpu; - - if (flags & RESET_CPU) { - if (flags & SET_ESA390) { - /* FIXME: set the arch mode to ESA/390 */ - } - - /* - * FIXME: clear interruptions: - * - PROG - * - SVC - * - local EXT (floating EXT are NOT cleared) - * - MCHECK (floating are NOT cleared) - */ - - cpu->state = GUEST_STOPPED; - } - - if (flags & RESET_PSW) - memset(&cpu->sie_cb.gpsw, 0, sizeof(struct psw)); - - if (flags & RESET_PREFIX) - cpu->sie_cb.prefix = 0; - - if (flags & RESET_CPU_TIMER) { - /* FIXME */ - } - - if (flags & RESET_CLK_COMP) { - /* FIXME */ - } - - if (flags & RESET_TOD_PROG_REG) { - /* FIXME */ - } - - if (flags & RESET_CR) { - memset(cpu->sie_cb.gcr, 0, 16*sizeof(u64)); - cpu->sie_cb.gcr[0] = 0xE0UL; - cpu->sie_cb.gcr[14] = 0xC2000000UL; - } - - if (flags & RESET_BREAK_EV_ADDR) { - /* FIXME: initialize to 0x1 */ - } - - if (flags & RESET_FPCR) - cpu->regs.fpcr = 0; - - if (flags & RESET_AR) - memset(cpu->regs.ar, 0, 16*sizeof(u32)); - - if (flags & RESET_GPR) - memset(cpu->regs.gpr, 0, 16*sizeof(u64)); - - if (flags & RESET_FPR) - memset(cpu->regs.fpr, 0, 16*sizeof(u64)); - - if (flags & RESET_STORAGE_KEYS) { - } - - if (flags & RESET_STORAGE) { - struct page *p; - - list_for_each_entry(p, &sys->guest_pages, guest) - memset(page_to_addr(p), 0, PAGE_SIZE); - } - - if (flags & RESET_NONVOL_STORAGE) { - } - - if (flags & RESET_EXPANDED_STORAGE) { - } - - if (flags & RESET_TOD) { - } - - if (flags & RESET_TOD_STEER) { - } - - if (flags & RESET_PLO_LOCKS) { - /* - * TODO: if RESET_PLO_LOCKS_PRESERVE is set, don't reset - * locks held by powered on CPUS - */ - } -} - -static void __perform_noncpu_reset(struct virt_sys *sys, int flags) -{ - if (flags & RESET_FLOATING_INTERRUPTIONS) { - } - - if (flags & RESET_IO) { - } -} - -/**************/ - -void guest_power_on_reset(struct virt_sys *sys) -{ - __perform_cpu_reset(sys, POWER_ON_RESET_FLAGS); - __perform_noncpu_reset(sys, POWER_ON_RESET_FLAGS); -} - -void guest_system_reset_normal(struct virt_sys *sys) -{ - __perform_cpu_reset(sys, CPU_RESET_FLAGS); - - /* - * TODO: once we have SMP guests, all other cpus should get a - * CPU_RESET_FLAGS as well. - */ - - __perform_noncpu_reset(sys, SUBSYSTEM_RESET_FLAGS); -} - -void guest_system_reset_clear(struct virt_sys *sys) -{ - __perform_cpu_reset(sys, CLEAR_RESET_FLAGS); - - /* - * TODO: once we have SMP guests, all other cpus should get a - * CLEAR_RESET_FLAGS as well. - */ - - __perform_noncpu_reset(sys, CLEAR_RESET_FLAGS); -} - -void guest_load_normal(struct virt_sys *sys) -{ - __perform_cpu_reset(sys, INIT_CPU_RESET_FLAGS); - - /* - * TODO: once we have SMP guests, all other cpus should get a - * CPU_RESET_FLAGS. - */ - - __perform_noncpu_reset(sys, SUBSYSTEM_RESET_FLAGS); -} - -void guest_load_clear(struct virt_sys *sys) -{ - __perform_cpu_reset(sys, CLEAR_RESET_FLAGS); - - /* - * TODO: once we have SMP guests, all other cpus should get a - * CLEAR_RESET_FLAGS as well. - */ - - __perform_noncpu_reset(sys, CLEAR_RESET_FLAGS); -}
--- a/sys/cp/splash.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -#include <splash.h> - -char *splash[] = { - " HH HH VV VV FFFFFFFFFFFF\n", - " HH HH VV VV FFFFFFFFFFFF\n", - " HH HH VV VV FF\n", - " HH HH VV VV FF\n", - " HH HH VV VV FF\n", - " HHHHHHHHHHHH VV VV FFFFFFF\n", - " HHHHHHHHHHHH VV VV FFFFFFF\n", - " HH HH VV VV FF\n", - " HH HH VV VV FF\n", - " HH HH VV VV FF\n", - " HH HH VVVV FF\n", - " HH HH VV FF\n", - "\n", - NULL, -};
--- a/sys/doc/.gitignore Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -commands
--- a/sys/doc/PSA.txt Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -Aside from the architecture defined storage locations in the PSA, HVF uses -the following addresses for special reasons: - -hex dec length reason - - 200 512 128 interrupt handler GPR storage - 280 640 16 PSW temporary storage - 290 656 8 current pointer
--- a/sys/doc/ipl.txt Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -This file attempts to describe what happens during IPL. - -NOTE: At the time, only IPL from tape and card reader is supported. - -1) system reads 24 bytes from the device - - a) bytes 0-7: new PSW, no interrupts, start address 0x800000 (8MB) - - IPL from tape: - - b) bytes 8-15: CCW to rewind the tape to previous TM - - c) bytes 16-23: CCW to read the entire loader to 0x800000 (8 MB) - - IPL from card reader: - - b) bytes 8-15: CCW to read 80 bytes (containing up to 10 CCWs) to - 0x18 - - c) bytes 16-23: CCW to read 24 bytes (containing up to 3 CCWs) to 0x68 - - Command chaining starts reading CCWs from addres 0x18 on. These read - the loader to 0x800000 (8 MB) - -2) arch mode is changed to z/Arch (see ipl/setmode.S) - -3) temporary stack is set up (R15 being the pointer) (see ipl/setmode.S) - -4) loader begins to execute: function load_nucleus (see ipl/loader.c) - - NOTE: loader.c use static inlines extensively, and thefore stack usage is - minimal - - a) If the IPL was from a tape, a CCW is issues to seek to the next TM - - b) nucleus is read from tape to 0x400000 (4 MB) - - NOTE: the data at 4MB just read is a 64-bit s390 ELF binary with Linux - ABI bits - - i) addition CCW address is set in the ORB - - ii) __readnucleus() is called; this function is implemented in - assembly (see ipl/loader_asm.S) - - iii) IO interrupt handler is set up (implemented in asm, see - ipl/loader_asm.S) - - iv) ORB is sent to the subchannel - - v) interrupts are enabled - - vi) a new PSW with wait state bit set is loaded - - vii) on IO interrupt - - 1) TSCH is issued to fill in a IRB - - 2) magic value (ORB int param) is checked - - 3) Device End flag is checked in the IRB - - NOTE: more checks should be performed here - - 4) If the device end flag is set, return to code that set up the - interrupt handler - - 5) otherwise, load up the old IO PSW (the one with the wait - state) - - viii)return to caller (back to ipl/loader.c) - - c) verify ELF header magic number, machine, type, etc. values - - d) traverse the section headers & copy data to final destination - - i) if the section type is PROGBITS (data stored in the ELF), copy - the data from it's temporary location to the desired location - (destination, offset within file, and length are all stored in - the section header) - this takes care of .text, .data, and - .rodata sections - - ii) if the section type is NOBITS (uninitialized storage, e.g., - .bss), do nothing, just assume that the location is a valid - location in memory - - iii) skip any other section types - - NOTE: SYMTAB and STRTAB section types should be copied to a useful - location to allow for symbols to be looked up during nucleus execution - - e) jump to the entry point as indicated by the ELF header - -At this point, the nucleus is executing.
--- a/sys/doc/memory.txt Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -Physical locations: - -------------------- (2^64)-1 -- -| | \ -| | | - . | - . \ - . > Generic pages - . / - . | -| | | -| | / -|-----------------| f(memsize)-- -| | \ -| | | - . \ - . > struct page array (see below) - . / -| | | -| | / -|-----------------| 4M -- -| | \ -| | | - . \ - . > OS .text, .data, .rodata, .bss - . / -| | | -| | / -|-----------------| 1M -- -| | \ -| | | - . | - . | - . \ -| | > PSA for each CPU -| | / -|-----------------| 8k | -| | | -| PSA | | -| | / -------------------- 0 -- - - -0 - 1MB: - Divided into up to 128 8KB chunks; nth chunk is nth CPU's PSA - (mapping done via the prefix register). - -1MB - 4MB: - OS .text - OS .data - OS .rodata - OS .bss - -4MB - (4MB + roundup((memsize >> PAGE_SIZE) * sizeof(struct page))): - This is an array of struct page entries for each page in the system. - The size varies based on the amount of memory installed. - -?? - (2^64)-1: - Generic pages; used for nucleus & process data - - These pages are managed by the buddy allocator. -
--- a/sys/drivers/3215.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -#include <device.h> -#include <console.h> -#include <list.h> -#include <sched.h> -#include <directory.h> - -static struct device_type d3215 = { - .types = LIST_HEAD_INIT(d3215.types), - .reg = NULL, - .interrupt = NULL, - .enable = console_enable, - .snprintf = NULL, - .type = 0x3215, - .model = 0, -}; - -int register_driver_3215(void) -{ - return register_device_type(&d3215); -} -
--- a/sys/drivers/Makefile Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -objs-drivers := device.o console.o 3215.o dasd.o vdevice.o
--- a/sys/drivers/console.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,387 +0,0 @@ -#include <console.h> -#include <slab.h> -#include <sched.h> -#include <directory.h> -#include <splash.h> -#include <vsprintf.h> - -/* - * List of all consoles on the system - */ -static LIST_HEAD(consoles); -static spinlock_t consoles_lock = SPIN_LOCK_UNLOCKED; - -static int read_io_int_handler(struct device *dev, struct io_op *ioop, struct irb *irb) -{ - struct console_line *cline; - struct ccw *ccw; - void *ptr; - - /* Device End is set, we're done */ - if (!(irb->scsw.dev_status & 0x04)) { - ioop->err = -EAGAIN; - return 0; - } - - ccw = (struct ccw*) (u64) ioop->orb.addr; - ptr = (void*) (u64) ccw->addr; - cline = container_of(ptr, struct console_line, buf); - - cline->len = strnlen((char*) cline->buf, CON_MAX_LINE_LEN-1); - cline->state = CON_STATE_IO; - - ioop->err = 0; - return 0; -} - -static void do_issue_read(struct console *con, struct io_op *ioop, struct ccw *ccws) -{ - struct console_line *cline; - int found; - - found = 0; - - atomic_dec(&con->dev->attention); - - spin_lock(&con->lock); - list_for_each_entry(cline, &con->read_lines, lines) { - if (cline->state != CON_STATE_FREE) - continue; - - cline->state = CON_STATE_PENDING; - found = 1; - break; - } - - if (!found) { - /* - * No unused console lines, time to allocate a new one - */ - cline = malloc(CON_LINE_ALLOC_SIZE, ZONE_NORMAL); - BUG_ON(!cline); - - cline->state = CON_STATE_PENDING; - list_add_tail(&cline->lines, &con->read_lines); - } - spin_unlock(&con->lock); - - /* clear the buffer to allow strlen on the result */ - memset(cline->buf, 0, CON_MAX_LINE_LEN); - - memset(ccws, 0, sizeof(struct ccw)); - - ccws[0].addr = ADDR31(cline->buf); - ccws[0].count = CON_MAX_LINE_LEN - 1; - ccws[0].cmd = 0x0a; - ccws[0].flags = CCW_FLAG_SLI; - - memset(&ioop->orb, 0, sizeof(struct orb)); - ioop->orb.lpm = 0xff; - ioop->orb.addr = ADDR31(ccws); - ioop->orb.f = 1; - - ioop->handler = read_io_int_handler; - ioop->dtor = NULL; - - submit_io(con->dev, ioop, CAN_SLEEP); -} - -/** - * console_flusher - iterates over a console's buffers and initiates the IO - */ -static int console_flusher(void *data) -{ - struct console *con = data; - struct console_line *cline; - int free_count; - int ccw_count; - - /* needed for the IO */ - struct io_op ioop; - struct ccw ccws[CON_MAX_FLUSH_LINES]; - - for(;;) { - if (atomic_read(&con->dev->attention)) - do_issue_read(con, &ioop, ccws); - - spin_lock(&con->lock); - - /* - * free all the lines we just finished the IO for - */ - free_count = 0; - list_for_each_entry(cline, &con->write_lines, lines) { - if (cline->state != CON_STATE_IO) - continue; - - cline->state = CON_STATE_FREE; - free_count++; - - if (free_count > CON_MAX_FREE_LINES) { - list_del(&cline->lines); - free(cline); - } - } - - /* - * find at most CON_MAX_FLUSH_LINES of CON_STATE_PENDING - * lines and shove necessary information into the right - * CCW - */ - ccw_count = 0; - list_for_each_entry(cline, &con->write_lines, lines) { - if (ccw_count >= CON_MAX_FLUSH_LINES) - break; - - if (cline->state != CON_STATE_PENDING) - continue; - - cline->state = CON_STATE_IO; - - ccws[ccw_count].addr = ADDR31(cline->buf); - ccws[ccw_count].count = cline->len; - ccws[ccw_count].cmd = 0x01; /* write */ - ccws[ccw_count].flags = CCW_FLAG_CC | CCW_FLAG_SLI; - - ccw_count++; - } - - /* - * We don't need the lock anymore - */ - spin_unlock(&con->lock); - - /* - * Anything to do? - */ - if (!ccw_count) { - schedule(); - continue; - } - - /* - * Clear Command-Chaining on the last CCW - */ - ccws[ccw_count-1].flags &= ~CCW_FLAG_CC; - - /* - * Now, set up the ORB and CCW - */ - memset(&ioop.orb, 0, sizeof(struct orb)); - ioop.orb.lpm = 0xff; - ioop.orb.addr = ADDR31(ccws); - ioop.orb.f = 1; /* format 1 CCW */ - - /* - * Set up the operation handler pointers, and start the IO - */ - ioop.handler = NULL; - ioop.dtor = NULL; - - submit_io(con->dev, &ioop, CAN_SLEEP); - } - - return 0; -} - -/** - * register_console - generic device registration callback - * @dev: console device to register - */ -static int register_console(struct device *dev) -{ - struct console *con; - struct console_line *cline; - - dev_get(dev); - - con = malloc(sizeof(struct console), ZONE_NORMAL); - BUG_ON(!con); - - con->sys = NULL; - con->dev = dev; - con->lock = SPIN_LOCK_UNLOCKED; - INIT_LIST_HEAD(&con->write_lines); - INIT_LIST_HEAD(&con->read_lines); - - /* - * alloc one read-line - */ - cline = malloc(CON_LINE_ALLOC_SIZE, ZONE_NORMAL); - BUG_ON(!cline); - cline->state = CON_STATE_FREE; - list_add(&cline->lines, &con->read_lines); - - spin_lock(&consoles_lock); - list_add_tail(&con->consoles, &consoles); - spin_unlock(&consoles_lock); - - return 0; -} - -static void print_splash(struct console *con) -{ - int i; - - for(i = 0; splash[i]; i++) - con_printf(con, splash[i]); - - con_printf(con, "HVF VERSION " VERSION "\n\n"); -} - -struct console* start_oper_console(void) -{ - struct device *dev; - - /* - * We only start the operator console - */ - - dev = find_device_by_ccuu(OPER_CONSOLE_CCUU); - BUG_ON(IS_ERR(dev)); - - return console_enable(dev); -} - -void* console_enable(struct device *dev) -{ - char name[TASK_NAME_LEN+1]; - struct console *con; - - con = find_console(dev); - if (!IS_ERR(con)) - return con; - - if (register_console(dev)) - return ERR_PTR(-ENOMEM); - - /* try again, this time, we should always find it! */ - con = find_console(dev); - if (IS_ERR(con)) - return con; - - atomic_inc(&con->dev->in_use); - - snprintf(name, TASK_NAME_LEN, "%05X-conflsh", con->dev->sch); - - create_task(name, console_flusher, con); - - print_splash(con); - - return con; -} - -int con_read_pending(struct console *con) -{ - struct console_line *cline; - int ret = 0; - - spin_lock(&con->lock); - - list_for_each_entry(cline, &con->read_lines, lines) { - if (cline->state == CON_STATE_IO) { - ret = 1; - break; - } - } - - spin_unlock(&con->lock); - - return ret; -} - -int con_read(struct console *con, u8 *buf, int size) -{ - struct console_line *cline; - int len; - - spin_lock(&con->lock); - - list_for_each_entry(cline, &con->read_lines, lines) { - if (cline->state == CON_STATE_IO) - goto found; - } - - spin_unlock(&con->lock); - - return -1; - -found: - len = (size-1 < cline->len) ? size-1 : cline->len; - - memcpy(buf, cline->buf, len); - buf[len] = '\0'; - - cline->state = CON_STATE_FREE; - - spin_unlock(&con->lock); - - return len; -} - -int con_write(struct console *con, u8 *buf, int len) -{ - int bytes = 0; - struct console_line *cline; - - spin_lock(&con->lock); - - list_for_each_entry(cline, &con->write_lines, lines) { - if (cline->state == CON_STATE_FREE) - goto found; - } - - /* None found, can we allocate a new one? */ - cline = malloc(CON_LINE_ALLOC_SIZE, ZONE_NORMAL); - if (!cline) - goto abort; - - list_add_tail(&cline->lines, &con->write_lines); - -found: - cline->state = CON_STATE_PENDING; - - cline->len = (len < CON_MAX_LINE_LEN) ? len : CON_MAX_LINE_LEN; - memcpy(cline->buf, buf, cline->len); - - /* - * All done here. The async thread will pick up the line of text, - * and issue the IO. - */ - -abort: - spin_unlock(&con->lock); - - return bytes; -} - -void for_each_console(void (*f)(struct console *con)) -{ - struct console *con; - - if (!f) - return; - - spin_lock(&consoles_lock); - list_for_each_entry(con, &consoles, consoles) - f(con); - spin_unlock(&consoles_lock); -} - -struct console* find_console(struct device *dev) -{ - struct console *con; - - if (!dev) - return ERR_PTR(-ENOENT); - - spin_lock(&consoles_lock); - list_for_each_entry(con, &consoles, consoles) { - if (con->dev == dev) - goto found; - } - con = ERR_PTR(-ENOENT); -found: - spin_unlock(&consoles_lock); - return con; -}
--- a/sys/drivers/dasd.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,276 +0,0 @@ -#include <device.h> -#include <console.h> -#include <list.h> -#include <io.h> -#include <sched.h> -#include <vsprintf.h> - -static int d3390_snprintf(struct device *dev, char* buf, int len) -{ - return snprintf(buf, len, "%10d CYL ", dev->eckd.cyls); -} - -static inline unsigned int ceil_quot(unsigned int d1, unsigned int d2) -{ - return (d1 + (d2 - 1)) / d2; -} - -static inline int d3390_recs_per_track(int kl, int dl) -{ - int dn, kn; - - dn = ceil_quot(dl + 6, 232) + 1; - if (kl) { - kn = ceil_quot(kl + 6, 232) + 1; - return 1729 / (10 + 9 + ceil_quot(kl + 6 * kn, 34) + - 9 + ceil_quot(dl + 6 * dn, 34)); - } else - return 1729 / (10 + 9 + ceil_quot(dl + 6 * dn, 34)); -} - -static int d3390_reg(struct device *dev) -{ - struct io_op ioop; - struct ccw ccw; - int ret; - u8 buf[64]; - - switch(dev->model) { - case 0x02: /* 3390, 3390-1 */ - case 0x06: /* 3390-2 */ - case 0x0a: /* 3390-3 */ - case 0x0c: /* 3390-9, 3390-27, 3390-J, 3390-54, 3390-JJ */ - break; - default: - return -ENOENT; - } - - /* - * Set up IO op for Read Device Characteristics - */ - ioop.handler = NULL; - ioop.dtor = NULL; - - memset(&ioop.orb, 0, sizeof(struct orb)); - ioop.orb.lpm = 0xff; - ioop.orb.addr = ADDR31(&ccw); - ioop.orb.f = 1; - - memset(&ccw, 0, sizeof(struct ccw)); - ccw.cmd = 0x64; /* RDC */ - ccw.flags = CCW_FLAG_SLI; - ccw.count = 64; - ccw.addr = ADDR31(buf); - - /* - * issue RDC - */ - ret = submit_io(dev, &ioop, CAN_LOOP); - if (ret) - return ret; - - dev->eckd.cyls = (buf[12] << 8) | - buf[13]; - dev->eckd.tracks = (buf[14] << 8) | - buf[15]; - dev->eckd.recs = d3390_recs_per_track(0, 4096); - dev->eckd.sectors = buf[16]; - dev->eckd.len = (buf[18] << 8) | - buf[19]; - - dev->eckd.formula = buf[22]; - if (dev->eckd.formula == 1) { - dev->eckd.f1 = buf[23]; - dev->eckd.f2 = (buf[24] << 8) | - buf[25]; - dev->eckd.f3 = (buf[26] << 8) | - buf[27]; - dev->eckd.f4 = 0; - dev->eckd.f5 = 0; - } else if (dev->eckd.formula == 2) { - dev->eckd.f1 = buf[23]; - dev->eckd.f2 = buf[24]; - dev->eckd.f3 = buf[25]; - dev->eckd.f4 = buf[26]; - dev->eckd.f5 = buf[27]; - } else - return -EINVAL; - - return 0; -} - -static int d3390_read(struct device *dev, u8 *buf, int lba) -{ - struct io_op ioop; - struct ccw ccw[4]; - u8 seek_data[6]; - u8 search_data[5]; - int ret; - - u16 cc, hh, r; - int rpt = dev->eckd.recs; - int rpc = dev->eckd.tracks * rpt; - - if (lba < 1) - return -EINVAL; - - lba--; - cc = lba / rpc; - hh = (lba % rpc) / rpt; - r = (lba % rpc) % rpt; - r++; - - /* - * Set up IO op - */ - ioop.handler = NULL; - ioop.dtor = NULL; - - memset(&ioop.orb, 0, sizeof(struct orb)); - ioop.orb.lpm = 0xff; - ioop.orb.addr = ADDR31(ccw); - ioop.orb.f = 1; - - memset(ccw, 0, sizeof(ccw)); - - /* SEEK */ - ccw[0].cmd = 0x07; - ccw[0].flags = CCW_FLAG_CC | CCW_FLAG_SLI; - ccw[0].count = 6; - ccw[0].addr = ADDR31(seek_data); - - seek_data[0] = 0; /* zero */ - seek_data[1] = 0; /* zero */ - seek_data[2] = cc >> 8; /* Cc */ - seek_data[3] = cc & 0xff; /* cC */ - seek_data[4] = hh >> 8; /* Hh */ - seek_data[5] = hh & 0xff; /* hH */ - - /* SEARCH */ - ccw[1].cmd = 0x31; - ccw[1].flags = CCW_FLAG_CC | CCW_FLAG_SLI; - ccw[1].count = 5; - ccw[1].addr = ADDR31(search_data); - - search_data[0] = cc >> 8; - search_data[1] = cc & 0xff; - search_data[2] = hh >> 8; - search_data[3] = hh & 0xff; - search_data[4] = r; - - /* TIC */ - ccw[2].cmd = 0x08; - ccw[2].flags = 0; - ccw[2].count = 0; - ccw[2].addr = ADDR31(&ccw[1]); - - /* READ DATA */ - ccw[3].cmd = 0x86; - ccw[3].flags = 0; - ccw[3].count = 4096; - ccw[3].addr = ADDR31(buf); - - /* - * issue IO - */ - ret = submit_io(dev, &ioop, CAN_SLEEP); - return ret; -} - -static struct device_type d3390 = { - .types = LIST_HEAD_INIT(d3390.types), - .reg = d3390_reg, - .interrupt = NULL, - .enable = NULL, - .snprintf = d3390_snprintf, - - .read = d3390_read, - - .type = 0x3390, - .all_models = 1, -}; - -/******************************************************************************/ - -static int d9336_snprintf(struct device *dev, char* buf, int len) -{ - return snprintf(buf, len, "%10d BLK ", dev->fba.blks); -} - -static int d9336_reg(struct device *dev) -{ - struct io_op ioop; - struct ccw ccw; - int ret; - u8 buf[64]; - - switch(dev->model) { - case 0x00: /* 9336-10 */ - case 0x10: /* 9336-20 */ - break; - default: - return -ENOENT; - } - - /* - * Set up IO op for Read Device Characteristics - */ - ioop.handler = NULL; - ioop.dtor = NULL; - - memset(&ioop.orb, 0, sizeof(struct orb)); - ioop.orb.lpm = 0xff; - ioop.orb.addr = ADDR31(&ccw); - ioop.orb.f = 1; - - memset(&ccw, 0, sizeof(struct ccw)); - ccw.cmd = 0x64; /* RDC */ - ccw.flags = CCW_FLAG_SLI; - ccw.count = 64; - ccw.addr = ADDR31(buf); - - /* - * issue RDC - */ - ret = submit_io(dev, &ioop, CAN_LOOP); - if (ret) - return ret; - - dev->fba.blk_size = (buf[4] << 8) | buf[5]; - dev->fba.bpg = (buf[6] << 24) | - (buf[7] << 16) | - (buf[8] << 8) | - buf[9]; - dev->fba.bpp = (buf[10] << 24) | - (buf[11] << 16) | - (buf[12] << 8) | - buf[13]; - dev->fba.blks= (buf[14] << 24) | - (buf[15] << 16) | - (buf[16] << 8) | - buf[17]; - - return 0; -} - -static struct device_type d9336 = { - .types = LIST_HEAD_INIT(d9336.types), - .reg = d9336_reg, - .interrupt = NULL, - .enable = NULL, - .snprintf = d9336_snprintf, - .type = 0x9336, - .all_models = 1, -}; - -int register_driver_dasd(void) -{ - int ret; - - ret = register_device_type(&d3390); - if (ret) - return ret; - - return register_device_type(&d9336); -} -
--- a/sys/drivers/device.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,365 +0,0 @@ -#include <list.h> -#include <channel.h> -#include <io.h> -#include <slab.h> -#include <device.h> -#include <spinlock.h> -#include <sched.h> - -struct senseid_struct { - u8 __reserved; - u16 cu_type; - u8 cu_model; - u16 dev_type; - u8 dev_model; -} __attribute__((packed)); - -struct static_device { - u16 dev_num; - struct senseid_struct sense; -}; - -#define END_OF_STATIC_DEV_LIST 0xffff - -/* - * This defines staticly-configured devices - ugly but necessary for devices - * that fail to identify themseleves via Sense-ID - */ -static struct static_device static_device_list[] = { - { .dev_num = 0x0009, .sense = { .dev_type = 0x3215, .dev_model = 0 } }, - { .dev_num = END_OF_STATIC_DEV_LIST }, -}; - -/* - * We need this device temporarily because submit_io & friends assume that - * the device that's doing IO is on the device list. Unfortunately, that - * isn't the case during IO device scanning. We register this device type, - * and each device temporarily during the scan to make submit_io & friends - * happy. When we're done scanning, we unregister this type. - */ -static struct device_type __fake_dev_type = { - .types = LIST_HEAD_INIT(__fake_dev_type.types), - .reg = NULL, - .interrupt = NULL, - .snprintf = NULL, - .type = 0, - .model = 0, -}; - -static LIST_HEAD(device_types); -static spinlock_t dev_types_lock; - -static LIST_HEAD(devices); -static spinlock_t devs_lock; - -static void unregister_device_type(struct device_type *type) -{ - spin_lock(&dev_types_lock); - list_del(&type->types); - spin_unlock(&dev_types_lock); -} - -/** - * register_device_type - register a new device type/model - * @dev: device type to register - */ -int register_device_type(struct device_type *dev) -{ - struct device_type *entry; - - spin_lock(&dev_types_lock); - - list_for_each_entry(entry, &device_types, types) { - if (dev == entry || - (dev->type == entry->type && dev->model == entry->model)) { - spin_unlock(&dev_types_lock); - return -EEXIST; - } - } - - list_add_tail(&dev->types, &device_types); - - spin_unlock(&dev_types_lock); - - return 0; -} - -/** - * find_device_by_ccuu - find device struct by ccuu - * @ccuu: device ccuu to find - */ -struct device *find_device_by_ccuu(u16 ccuu) -{ - struct device *dev; - - spin_lock(&devs_lock); - - list_for_each_entry(dev, &devices, devices) { - if (dev->ccuu == ccuu) { - dev_get(dev); - spin_unlock(&devs_lock); - return dev; - } - } - - spin_unlock(&devs_lock); - - return ERR_PTR(-ENOENT); -} - -/** - * find_device_by_sch - find device struct by subchannel number - * @sch: device subchannel - */ -struct device *find_device_by_sch(u32 sch) -{ - struct device *dev; - - spin_lock(&devs_lock); - - list_for_each_entry(dev, &devices, devices) { - if (dev->sch == sch) { - dev_get(dev); - spin_unlock(&devs_lock); - return dev; - } - } - - spin_unlock(&devs_lock); - - return ERR_PTR(-ENOENT); -} - -/** - * find_device_by_type - find device struct by type/model - * @type: device type to find - * @model: device model to find - */ -struct device *find_device_by_type(u16 type, u8 model) -{ - struct device *dev; - - spin_lock(&devs_lock); - - list_for_each_entry(dev, &devices, devices) { - if (dev->type == type && - dev->model == model) { - dev_get(dev); - spin_unlock(&devs_lock); - return dev; - } - } - - spin_unlock(&devs_lock); - - return ERR_PTR(-ENOENT); -} - -/** - * __register_device - helper to register a device - * @dev: device to register - * @remove: remove the device from the list first - */ -static int __register_device(struct device *dev, int remove) -{ - struct device_type *type; - int err = 0; - - spin_double_lock(&devs_lock, &dev_types_lock); - - list_for_each_entry(type, &device_types, types) { - if (type->type == dev->type && - (type->all_models || - type->model == dev->model)) - goto found; - } - - err = -ENOENT; - type = NULL; - -found: - spin_double_unlock(&devs_lock, &dev_types_lock); - - atomic_set(&dev->refcnt, 1); - atomic_set(&dev->in_use, 0); - - dev->dev = type; - - if (type && type->reg) { - err = type->reg(dev); - - if (err) - dev->dev = NULL; - } - - spin_double_lock(&devs_lock, &dev_types_lock); - if (remove) - list_del(&dev->devices); - list_add_tail(&dev->devices, &devices); - spin_double_unlock(&devs_lock, &dev_types_lock); - - return err; -} - -static int do_sense_id(struct device *dev, u16 dev_num, struct senseid_struct *buf) -{ - struct io_op ioop; - struct ccw ccw; - int ret; - int idx; - struct static_device *sdev; - - /* - * Check static configuration; if device is found (by device - * number), use that information instead of issuing sense-id - */ - for(idx = 0; sdev = &static_device_list[idx], - sdev->dev_num != END_OF_STATIC_DEV_LIST; idx++) { - if (sdev->dev_num == dev_num) { - memcpy(buf, &sdev->sense, sizeof(struct senseid_struct)); - return 0; - } - } - - /* - * Set up IO op for Sense-ID - */ - ioop.handler = NULL; - ioop.dtor = NULL; - - memset(&ioop.orb, 0, sizeof(struct orb)); - ioop.orb.lpm = 0xff; - ioop.orb.addr = ADDR31(&ccw); - ioop.orb.f = 1; - - memset(&ccw, 0, sizeof(struct ccw)); - ccw.cmd = 0xe4; /* Sense-ID */ - ccw.flags = CCW_FLAG_SLI; - ccw.count = sizeof(struct senseid_struct); - ccw.addr = ADDR31(buf); - - /* - * issue SENSE-ID - */ - ret = submit_io(dev, &ioop, CAN_LOOP); - BUG_ON(ret); - - return ioop.err; -} - -/* - * Scan all subchannel ids, and register each device - */ -void scan_devices(void) -{ - struct schib schib; - struct device *dev = NULL; - struct senseid_struct buf; - u32 sch; - int ret; - - BUG_ON(register_device_type(&__fake_dev_type)); - - memset(&schib, 0, sizeof(struct schib)); - - /* - * For each possible subchannel id... - */ - for(sch = 0x10000; sch <= 0x1ffff; sch++) { - /* - * ...call store subchannel, to find out whether or not - * there is a device - */ - if (store_sch(sch, &schib)) - continue; - - if (!schib.pmcw.v) - continue; - - /* - * The following code tries to take the following steps: - * - alloc device struct - * - enable the subchannel - * - MSCH - * - issue SENSE-ID IO op & wait for completion - * - register device with apropriate subsystem - */ - - if (!dev) { - dev = malloc(sizeof(struct device), ZONE_NORMAL); - - /* - * if we failed to allocate memory, there's not much we can - * do - */ - BUG_ON(!dev); - - atomic_set(&dev->attention, 0); - INIT_LIST_HEAD(&dev->q_out); - dev->dev = &__fake_dev_type; - } - - schib.pmcw.e = 1; - - if (modify_sch(sch, &schib)) - continue; - - dev->sch = sch; - BUG_ON(__register_device(dev, 0)); - BUG_ON(dev->dev != &__fake_dev_type); - - /* - * Find out what the device is - whichever way is necessary - */ - ret = do_sense_id(dev, schib.pmcw.dev_num, &buf); - - if (ret) - continue; - - dev->type = buf.dev_type; - dev->model = buf.dev_model; - dev->ccuu = schib.pmcw.dev_num; - - /* __register_device will remove the fake entry! */ - if (__register_device(dev, 1)) { - /* - * error registering ... the device struct MUST NOT - * be freed as it has been added onto the devices - * list. All that needs to be done is to reset the - * enabled bit. - */ - schib.pmcw.e = 0; - - /* msch could fail, but it shouldn't be fatal */ - modify_sch(sch, &schib); - } - - /* to prevent a valid device struct from being free'd */ - dev = NULL; - } - - unregister_device_type(&__fake_dev_type); - - free(dev); -} - -void list_devices(struct console *con, void (*f)(struct console*, struct device*)) -{ - struct device *dev; - - spin_lock(&devs_lock); - - list_for_each_entry(dev, &devices, devices) { - dev_get(dev); - f(con, dev); - dev_put(dev); - } - - spin_unlock(&devs_lock); -} - -void register_drivers(void) -{ - register_driver_3215(); - register_driver_dasd(); -}
--- a/sys/drivers/vdevice.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -#include <slab.h> -#include <list.h> -#include <vdevice.h> - -static int __setup_vdev_ded(struct virt_sys *sys, - struct directory_vdev *dirdev, - struct virt_device *vdev) -{ - struct device *rdev; - - rdev = find_device_by_ccuu(dirdev->u.dedicate.rdev); - if (IS_ERR(rdev)) - return PTR_ERR(rdev); - - atomic_inc(&rdev->in_use); - - vdev->u.dedicate.rdev = rdev; - vdev->type = rdev->type; - vdev->model = rdev->model; - - return 0; -} - -int alloc_virt_dev(struct virt_sys *sys, struct directory_vdev *dirdev, - u32 sch) -{ - struct virt_device *vdev; - int ret = 0; - - vdev = malloc(sizeof(struct virt_device), ZONE_NORMAL); - if (!vdev) - return -ENOMEM; - - vdev->vtype = dirdev->type; - vdev->sch = sch; - vdev->pmcw.v = 1; - vdev->pmcw.dev_num = dirdev->vdev; - vdev->pmcw.lpm = 0x80; - vdev->pmcw.pim = 0x80; - vdev->pmcw.pom = 0xff; - vdev->pmcw.pam = 0x80; - - switch(dirdev->type) { - case VDEV_CONS: - vdev->type = 0x3215; - vdev->model = 0; - break; - case VDEV_DED: - ret = __setup_vdev_ded(sys, dirdev, vdev); - break; - case VDEV_SPOOL: - vdev->type = dirdev->u.spool.type; - vdev->model = dirdev->u.spool.model; - // FIXME: hook it up to the spooler - break; - case VDEV_MDISK: - vdev->type = 0x3390; - vdev->model = 3; - // FIXME: hook it up to mdisk driver - break; - case VDEV_LINK: - goto free; - case VDEV_INVAL: - goto out; - } - - list_add_tail(&vdev->devices, &sys->virt_devs); - - return ret; - -free: - free(vdev); - return 0; - -out: - free(vdev); - return -EINVAL; -}
--- a/sys/fs/Makefile Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -objs-fs := bdev.o edf.o
--- a/sys/fs/bdev.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -#include <device.h> -#include <bdev.h> - -int bdev_read_block(struct device *dev, void *buf, int lba) -{ - if (!dev->dev->read) - return -EINVAL; - - return dev->dev->read(dev, buf, lba); -}
--- a/sys/fs/edf.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,171 +0,0 @@ -#include <mutex.h> -#include <buddy.h> -#include <slab.h> -#include <device.h> -#include <bdev.h> -#include <ebcdic.h> -#include <edf.h> - -struct fs *edf_mount(struct device *dev) -{ - struct page *page; - void *tmp; - struct fs *fs; - long ret; - - page = alloc_pages(0, ZONE_NORMAL); - if (!page) - return ERR_PTR(-ENOMEM); - tmp = page_to_addr(page); - - ret = -ENOMEM; - fs = malloc(sizeof(struct fs), ZONE_NORMAL); - if (!fs) - goto out_free; - - /* First, read & verify the label */ - ret = bdev_read_block(dev, tmp, EDF_LABEL_BLOCK_NO); - if (ret) - goto out_free; - - mutex_init(&fs->lock); - INIT_LIST_HEAD(&fs->files); - fs->dev = dev; - fs->tmp_buf = tmp; - - memcpy(&fs->ADT, tmp, sizeof(struct ADT)); - - ret = -EINVAL; - if ((fs->ADT.ADTIDENT != __ADTIDENT) || - (fs->ADT.ADTDBSIZ != EDF_SUPPORTED_BLOCK_SIZE) || - (fs->ADT.ADTOFFST != 0) || - (fs->ADT.ADTFSTSZ != sizeof(struct FST))) - goto out_free; - - return fs; - -out_free: - free(fs); - free_pages(tmp, 0); - return ERR_PTR(ret); -} - -extern struct console *oper_con; -struct file *edf_lookup(struct fs *fs, char *fn, char *ft) -{ - char __fn[8]; - char __ft[8]; - struct page *page; - struct file *file; - struct file *tmpf; - struct FST *fst; - long ret; - int found; - int i; - - file = malloc(sizeof(struct file), ZONE_NORMAL); - if (!file) - return ERR_PTR(-ENOMEM); - - file->fs = fs; - file->buf = NULL; - - memcpy(__fn, fn, 8); - memcpy(__ft, ft, 8); - ascii2ebcdic((u8 *) __fn, 8); - ascii2ebcdic((u8 *) __ft, 8); - - mutex_lock(&fs->lock); - - /* first, check the cache */ - list_for_each_entry(tmpf, &fs->files, files) { - if (!memcmp((char*) tmpf->FST.FSTFNAME, __fn, 8) && - !memcmp((char*) tmpf->FST.FSTFTYPE, __ft, 8)) { - mutex_unlock(&fs->lock); - free(file); - return tmpf; - } - } - - page = alloc_pages(0, ZONE_NORMAL); - if (!page) { - ret = -ENOMEM; - goto out_unlock; - } - file->buf = page_to_addr(page); - - /* oh well, must do it the hard way ... read from disk */ - ret = bdev_read_block(fs->dev, fs->tmp_buf, fs->ADT.ADTDOP); - if (ret) - goto out_unlock; - - fst = fs->tmp_buf; - - for(i=0,found=0; i<fs->ADT.ADTNFST; i++) { - if ((!memcmp(fst[i].FSTFNAME, __fn, 8)) && - (!memcmp(fst[i].FSTFTYPE, __ft, 8))) { - memcpy(&file->FST, &fst[i], sizeof(struct FST)); - found = 1; - break; - } - } - - if (!found) { - ret = -ENOENT; - goto out_unlock; - } - - mutex_init(&file->lock); - list_add_tail(&file->files, &fs->files); - - mutex_unlock(&fs->lock); - - return file; - -out_unlock: - if (file && file->buf) - free_pages(file->buf, 0); - mutex_unlock(&fs->lock); - free(file); - return ERR_PTR(ret); -} - -int edf_read_rec(struct file *file, char *buf, u32 recno) -{ - struct fs *fs = file->fs; - u32 fop, lrecl; - int ret; - - if (file->FST.FSTNLVL != 0 || - file->FST.FSTPTRSZ != 4 || - file->FST.FSTLRECL > fs->ADT.ADTDBSIZ || - file->FST.FSTRECFM != FSTDFIX) - return -EINVAL; - - mutex_lock(&file->lock); - - fop = file->FST.FSTFOP; - lrecl = file->FST.FSTLRECL; - - ret = bdev_read_block(fs->dev, file->buf, fop); - if (ret) - goto out; - - memcpy(buf, file->buf + (recno * lrecl), lrecl); - -out: - mutex_unlock(&file->lock); - - return ret; -} - -void edf_file_free(struct file *file) -{ - struct fs *fs = file->fs; - - mutex_lock(&fs->lock); - list_del(&file->files); - mutex_unlock(&fs->lock); - - free(file); -}
--- a/sys/hvf.directory Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -USER OPERATOR A - MACHINE ESA 1 - STORAGE 17M - CONSOLE 0009 3215 - SPOOL 000C 3505 READER - SPOOL 000D 3525 PUNCH - SPOOL 000E 1403 PRINT - MDISK 0191 3390 15 100 0192 - -USER JEFFPC A - MACHINE ESA 1 - STORAGE 64M - CONSOLE 0009 3215 - SPOOL 000C 3505 READER - SPOOL 000D 3525 PUNCH - SPOOL 000E 1403 PRINT - MDISK 0190 3390 15 100 0192 - -USER OBIWAN G - MACHINE ESA 1 - STORAGE 2M - CONSOLE 0009 3215 - SPOOL 000C 3505 READER - SPOOL 000D 3525 PUNCH - SPOOL 000E 1403 PRINT - MDISK 0193 3390 15 100 0192
--- a/sys/include/atomic.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,203 +0,0 @@ -/* - * Based on atomic.h from Linux Kernel - */ - -#ifndef __ARCH_S390_ATOMIC__ -#define __ARCH_S390_ATOMIC__ - -/* - * include/asm-s390/atomic.h - * - * S390 version - * Copyright (C) 1999-2005 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), - * Denis Joseph Barrow, - * Arnd Bergmann (arndb@de.ibm.com) - * - * Derived from "include/asm-i386/bitops.h" - * Copyright (C) 1992, Linus Torvalds - * - */ - -/* - * Atomic operations that C can't guarantee us. Useful for - * resource counting etc.. - * S390 uses 'Compare And Swap' for atomicity in SMP enviroment - */ - -typedef struct { - volatile int counter; -} __attribute__ ((aligned (4))) atomic_t; -#define ATOMIC_INIT(i) { (i) } - -#define __CS_LOOP(ptr, op_val, op_string) ({ \ - typeof(ptr->counter) old_val, new_val; \ - asm volatile( \ - " l %0,%2\n" \ - "0: lr %1,%0\n" \ - op_string " %1,%3\n" \ - " cs %0,%1,%2\n" \ - " jl 0b" \ - : "=&d" (old_val), "=&d" (new_val), \ - "=Q" (((atomic_t *)(ptr))->counter) \ - : "d" (op_val), "Q" (((atomic_t *)(ptr))->counter) \ - : "cc", "memory"); \ - new_val; \ -}) - -#define atomic_read(v) ((v)->counter) -#define atomic_set(v,i) (((v)->counter) = (i)) - -static __inline__ int atomic_add_return(int i, atomic_t * v) -{ - return __CS_LOOP(v, i, "ar"); -} -#define atomic_add(_i, _v) atomic_add_return(_i, _v) -#define atomic_add_negative(_i, _v) (atomic_add_return(_i, _v) < 0) -#define atomic_inc(_v) atomic_add_return(1, _v) -#define atomic_inc_return(_v) atomic_add_return(1, _v) -#define atomic_inc_and_test(_v) (atomic_add_return(1, _v) == 0) - -static __inline__ int atomic_sub_return(int i, atomic_t * v) -{ - return __CS_LOOP(v, i, "sr"); -} -#define atomic_sub(_i, _v) atomic_sub_return(_i, _v) -#define atomic_sub_and_test(_i, _v) (atomic_sub_return(_i, _v) == 0) -#define atomic_dec(_v) atomic_sub_return(1, _v) -#define atomic_dec_return(_v) atomic_sub_return(1, _v) -#define atomic_dec_and_test(_v) (atomic_sub_return(1, _v) == 0) - -static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t * v) -{ - __CS_LOOP(v, ~mask, "nr"); -} - -static __inline__ void atomic_set_mask(unsigned long mask, atomic_t * v) -{ - __CS_LOOP(v, mask, "or"); -} - -#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) - -static __inline__ int atomic_cmpxchg(atomic_t *v, int old, int new) -{ - asm volatile( - " cs %0,%2,%1" - : "+d" (old), "=Q" (v->counter) - : "d" (new), "Q" (v->counter) - : "cc", "memory"); - return old; -} - -static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) -{ - int c, old; - c = atomic_read(v); - for (;;) { - if (unlikely(c == u)) - break; - old = atomic_cmpxchg(v, c, c + a); - if (likely(old == c)) - break; - c = old; - } - return c != u; -} - -#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) - -#undef __CS_LOOP - -typedef struct { - volatile long long counter; -} __attribute__ ((aligned (8))) atomic64_t; -#define ATOMIC64_INIT(i) { (i) } - -#define __CSG_LOOP(ptr, op_val, op_string) ({ \ - typeof(ptr->counter) old_val, new_val; \ - asm volatile( \ - " lg %0,%2\n" \ - "0: lgr %1,%0\n" \ - op_string " %1,%3\n" \ - " csg %0,%1,%2\n" \ - " jl 0b" \ - : "=&d" (old_val), "=&d" (new_val), \ - "=Q" (((atomic_t *)(ptr))->counter) \ - : "d" (op_val), "Q" (((atomic_t *)(ptr))->counter) \ - : "cc", "memory" ); \ - new_val; \ -}) - -#define atomic64_read(v) ((v)->counter) -#define atomic64_set(v,i) (((v)->counter) = (i)) - -static __inline__ long long atomic64_add_return(long long i, atomic64_t * v) -{ - return __CSG_LOOP(v, i, "agr"); -} -#define atomic64_add(_i, _v) atomic64_add_return(_i, _v) -#define atomic64_add_negative(_i, _v) (atomic64_add_return(_i, _v) < 0) -#define atomic64_inc(_v) atomic64_add_return(1, _v) -#define atomic64_inc_return(_v) atomic64_add_return(1, _v) -#define atomic64_inc_and_test(_v) (atomic64_add_return(1, _v) == 0) - -static __inline__ long long atomic64_sub_return(long long i, atomic64_t * v) -{ - return __CSG_LOOP(v, i, "sgr"); -} -#define atomic64_sub(_i, _v) atomic64_sub_return(_i, _v) -#define atomic64_sub_and_test(_i, _v) (atomic64_sub_return(_i, _v) == 0) -#define atomic64_dec(_v) atomic64_sub_return(1, _v) -#define atomic64_dec_return(_v) atomic64_sub_return(1, _v) -#define atomic64_dec_and_test(_v) (atomic64_sub_return(1, _v) == 0) - -static __inline__ void atomic64_clear_mask(unsigned long mask, atomic64_t * v) -{ - __CSG_LOOP(v, ~mask, "ngr"); -} - -static __inline__ void atomic64_set_mask(unsigned long mask, atomic64_t * v) -{ - __CSG_LOOP(v, mask, "ogr"); -} - -#define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) - -static __inline__ long long atomic64_cmpxchg(atomic64_t *v, - long long old, long long new) -{ - asm volatile( - " csg %0,%2,%1" - : "+d" (old), "=Q" (v->counter) - : "d" (new), "Q" (v->counter) - : "cc", "memory"); - return old; -} - -static __inline__ int atomic64_add_unless(atomic64_t *v, - long long a, long long u) -{ - long long c, old; - c = atomic64_read(v); - for (;;) { - if (unlikely(c == u)) - break; - old = atomic64_cmpxchg(v, c, c + a); - if (likely(old == c)) - break; - c = old; - } - return c != u; -} - -#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) - -#undef __CSG_LOOP - -#define smp_mb__before_atomic_dec() smp_mb() -#define smp_mb__after_atomic_dec() smp_mb() -#define smp_mb__before_atomic_inc() smp_mb() -#define smp_mb__after_atomic_inc() smp_mb() - -#endif /* __ARCH_S390_ATOMIC__ */
--- a/sys/include/bdev.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -#ifndef __BDEV_H -#define __BDEV_H - -extern int bdev_read_block(struct device *dev, void *buf, int lba); - -#endif
--- a/sys/include/buddy.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -#ifndef __BUDDY_H -#define __BUDDY_H - -#include <page.h> - -extern void init_buddy_alloc(u64 start); -extern struct page *alloc_pages(int order, int type); -extern void free_pages(void *ptr, int order); - -#endif
--- a/sys/include/channel.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,302 +0,0 @@ -#ifndef __CHANNEL_H -#define __CHANNEL_H - -/* - * We only care about format-1 CCWs - */ -struct ccw { - u8 cmd; /* Command code */ - u8 flags; /* Flags */ - u16 count; /* Count */ - u32 addr; /* Data Address */ -} __attribute__((packed,aligned(8))); - -struct ccw0 { - u8 cmd; /* Command code */ - u8 addr_hi; /* Data Address (bits 8-15) */ - u16 addr_lo; /* Data Address (bits 16-31) */ - u8 flags; /* Flags */ - u8 _res0; - u16 count; /* Count */ -} __attribute__((packed,aligned(8))); - -#define CCW_CMD_IPL_READ 0x02 -#define CCW_CMD_NOP 0x03 -#define CCW_CMD_BASIC_SENSE 0x04 -#define CCW_CMD_SENSE_ID 0xe4 -#define CCW_CMD_TIC 0x08 - -#define CCW_FLAG_CD 0x80 /* Chain-Data */ -#define CCW_FLAG_CC 0x40 /* Chain-Command */ -#define CCW_FLAG_SLI 0x20 /* Suppress-Length-Indication */ -#define CCW_FLAG_SKP 0x10 /* Skip */ -#define CCW_FLAG_PCI 0x08 /* Program-Controlled-Interruption */ -#define CCW_FLAG_IDA 0x04 /* Indirect-Data-Address */ -#define CCW_FLAG_S 0x02 /* Suspend */ -#define CCW_FLAG_MIDA 0x01 /* Modified-Indirect-Data-Address */ - -/* - * ORB - */ -struct orb { - /* word 0 */ - u32 param; /* Interruption Parameter */ - - /* word 1 */ - u8 key:4, /* Subchannel Key */ - s:1, /* Suspend */ - c:1, /* Streaming-Mode Control */ - m:1, /* Modification Control */ - y:1; /* Synchronization Control */ - u8 f:1, /* Format Control */ - p:1, /* Prefetch Control */ - i:1, /* Initial-Status-Interruption Control */ - a:1, /* Address-Limit-Checking control */ - u:1, /* Suppress-Suspend-Interruption Control */ - __zero1:1, - h:1, /* Format-2-IDAW Control */ - t:1; /* 2K-IDAW Control */ - u8 lpm; /* Logical-Path Mask */ - u8 l:1, /* Incorrect-Length-Suppression Mode */ - d:1, /* Modified-CCW-Indirect-Data-Addressing Control */ - __zero2:5, - x:1; /* ORB-Extension Control */ - - /* word 2 */ - u32 addr; /* Channel-Program Address */ - - /* word 3 */ - u8 css_prio; /* Channel-Subsystem Priority */ - u8 __reserved1; - u8 cu_prio; /* Control-Unit Priority */ - u8 __reserved2; - - /* word 4 - 7 */ - u32 __reserved3; - u32 __reserved4; - u32 __reserved5; - u32 __reserved6; -} __attribute__((packed,aligned(4))); - -enum SCSW_FC { - FC_CLEAR = 0x10, - FC_HALT = 0x20, - FC_START = 0x40, -}; - -enum SCSW_SC { - SC_STATUS = 0x01, - SC_SECONDARY = 0x02, - SC_PRIMARY = 0x04, - SC_INTERMED = 0x08, - SC_ALERT = 0x10, -}; - -struct scsw { - /* word 0 */ - u16 key:4, /* Subchannel key */ - s:1, /* Suspend control */ - l:1, /* ESW format */ - cc:2, /* Deferred condition code */ - f:1, /* Format */ - p:1, /* Prefetch */ - i:1, /* Initial-status interruption control */ - a:1, /* Address-limit-checking control */ - u:1, /* Supress-suspended interruption */ - z:1, /* Zero condition code */ - e:1, /* Extended control */ - n:1; /* Path no operational */ - u16 __zero:1, - fc:3, /* Function control */ - ac:8, /* Activity control */ - sc:4; /* Status control */ - - /* word 1 */ - u32 addr; /* CCW Address */ - - /* word 2 */ - u8 dev_status; /* Device status */ - u8 sch_status; /* Subchannel status */ - u16 count; /* Count */ -} __attribute__((packed)); - -/* needed by IRB */ -struct irb_ext_status { - /* TODO: not implemented */ - u32 w0, w1, w2, w3, w4; -} __attribute__((packed)); - -/* needed by IRB */ -struct irb_ext_control { - /* TODO: not implemented */ - u32 w0, w1, w2, w3, w4, w5, w6, w7; -} __attribute__((packed)); - -/* needed by IRB */ -struct irb_ext_measurement { - /* TODO: not implemented */ - u32 w0, w1, w2, w3, w4, w5, w6, w7; -} __attribute__((packed)); - -struct irb { - struct scsw scsw; /* Subchannel-Status */ - struct irb_ext_status ext_status; /* Extended-Status */ - struct irb_ext_control ext_control; /* Extended-Control */ - struct irb_ext_measurement ext_measure; /* Extended-Measurement */ -} __attribute__((packed,aligned(4))); - -/* Path Management Control Word */ -struct pmcw { - /* word 0 */ - u32 interrupt_param; /* Interruption Parameter */ - - /* word 1*/ - u8 __zero1:2, - isc:3, /* I/O-Interruption-Subclass Code */ - __zero2:3; - u8 e:1, /* Enabled */ - lm:2, /* Limit Mode */ - mm:2, /* Measurement-Mode Enable */ - d:1, /* Multipath Mode */ - t:1, /* Timing Facility */ - v:1; /* Device Number Valid */ - u16 dev_num; /* Device Number */ - - /* word 2 */ - u8 lpm; /* Logical-Path Mask */ - u8 pnom; /* Path-Not-Operational Mask */ - u8 lpum; /* Last-Path-Used Mask */ - u8 pim; /* Path-Installed Mask */ - - /* word 3 */ - u16 mbi; /* Measurement-Block Index */ - u8 pom; /* Path-Operational Mask */ - u8 pam; /* Path-Available Mask */ - - /* word 4 & 5 */ - u8 chpid[8]; /* Channel-Path Identifiers */ - - /* word 6 */ - u16 __zero3; - u16 __zero4:13, - f:1, /* Measurement Block Format Control */ - x:1, /* Extended Measurement Word Mode Enable */ - s:1; /* Concurrent Sense */ -}; - -/* needed by schib */ -struct schib_measurement_block { - /* TODO: not implemented */ - u32 w0, w1; -}; - -struct schib { - struct pmcw pmcw; /* Path Management Control Word */ - struct scsw scsw; /* Subchannel Status Word */ - union { - struct schib_measurement_block measure_block; - }; - u32 model_dep_area; -} __attribute__((packed,aligned(4))); - -static inline int store_sch(u32 sch, struct schib *schib) -{ - int cc; - - asm volatile( - "lr %%r1,%2\n" - "stsch %1\n" - "ipm %0\n" - "srl %0,28\n" - : /* output */ - "=d" (cc), - "=Q" (*schib) - : /* input */ - "d" (sch) - : /* clobbered */ - "cc", "r1", "memory" - ); - - if (cc == 3) - return -EINVAL; - return 0; -} - -static inline int modify_sch(u32 sch, struct schib *schib) -{ - int cc; - - asm volatile( - "lr %%r1,%1\n" - "msch 0(%2)\n" - "ipm %0\n" - "srl %0,28\n" - : /* output */ - "=d" (cc) - : /* input */ - "d" (sch), - "a" (schib) - : /* clobbered */ - "cc", "r1" - ); - - if (cc == 1 || cc == 2) - return -EBUSY; - if (cc == 3) - return -EINVAL; - return 0; -} - -static inline int start_sch(u32 sch, struct orb *orb) -{ - int cc; - - asm volatile( - " lr %%r1,%1\n" - " ssch 0(%2)\n" - " ipm %0\n" - " srl %0,28\n" - : /* output */ - "=d" (cc) - : /* input */ - "d" (sch), - "a" (orb) - : /* clobbered */ - "cc", "r1" - ); - - if (cc == 1 || cc == 2) - return -EBUSY; - if (cc == 3) - return -EINVAL; - - return 0; -} - -static inline int test_sch(u32 sch, struct irb *irb) -{ - int cc; - - asm volatile( - " lr %%r1,%1\n" - " tsch 0(%2)\n" - " ipm %0\n" - " srl %0,28\n" - : /* output */ - "=d" (cc) - : /* input */ - "d" (sch), - "a" (irb) - : /* clobbered */ - "cc", "r1" - ); - - if (cc == 3) - return -EINVAL; - - return 0; -} - -extern void scan_devices(void); - -#endif
--- a/sys/include/compiler.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -#ifndef __COMPILER_H -#define __COMPILER_H - -/* - * For compatibility with some Linux kernel code - */ -#define likely(x) (x) -#define unlikely(x) (x) - -#endif
--- a/sys/include/config.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -#ifndef __CONFIG_H -#define __CONFIG_H - -/* - * Base address within a guest's address space; used as the base address for - * the IPL helper code. - * - * NOTE: It must be >= 16M, but <2G - */ -#define GUEST_IPL_BASE (16ULL * 1024ULL * 1024ULL) - -#define OPER_CONSOLE_CCUU 0x0009 - -#endif
--- a/sys/include/console.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -#ifndef __CONSOLE_H -#define __CONSOLE_H - -#include <device.h> -#include <io.h> -#include <spinlock.h> - -/* line allocation size */ -#define CON_LINE_ALLOC_SIZE 256 - -/* maximum line length */ -#define CON_MAX_LINE_LEN (CON_LINE_ALLOC_SIZE - sizeof(struct console_line)) - -/* maximum number of free lines to keep around */ -#define CON_MAX_FREE_LINES 32 - -/* number of lines of console text to flush at a time */ -#define CON_MAX_FLUSH_LINES 32 - -/* line state */ -#define CON_STATE_FREE 0 -#define CON_STATE_PENDING 1 -#define CON_STATE_IO 2 - -struct console_line { - struct list_head lines; - u16 len; - u16 state; - u8 buf[0]; -}; - -struct console { - struct list_head consoles; - struct virt_sys *sys; - struct device *dev; - spinlock_t lock; - struct list_head write_lines; - struct list_head read_lines; -}; - -extern int console_interrupt(struct device *dev, struct irb *irb); -extern struct console* start_oper_console(void); -extern void* console_enable(struct device *dev); -extern int con_read_pending(struct console *con); -extern int con_read(struct console *con, u8 *buf, int size); -extern int con_write(struct console *con, u8 *buf, int len); -extern void for_each_console(void (*f)(struct console *con)); -extern struct console* find_console(struct device *dev); - -#endif
--- a/sys/include/cp.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -#ifndef __CP_H -#define __CP_H - -#include <directory.h> - -#define CP_CMD_MAX_LEN 8 - -/* - * This file should contain only externally (from CP's point of view) - * visible interfaces. - */ -extern struct console *oper_con; - -extern void spawn_oper_cp(struct console *con); -extern void spawn_user_cp(struct console *con, struct user *u); -extern int invoke_cp_cmd(struct virt_sys *sys, char *cmd, int len); -extern int invoke_cp_logon(struct console *con, char *cmd, int len); - -extern void list_users(struct console *con, void (*f)(struct console *con, - struct virt_sys *sys)); - -/* All the different ways to reset the system */ -extern void guest_power_on_reset(struct virt_sys *sys); -extern void guest_system_reset_normal(struct virt_sys *sys); -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 run_guest(struct virt_sys *sys); -extern void handle_interception(struct virt_sys *sys); - -extern int handle_instruction(struct virt_sys *sys); -extern int handle_instruction_priv(struct virt_sys *sys); - -typedef int (*intercept_handler_t)(struct virt_sys *sys); - -#define CP_CMD_AUTH(s,a) do { \ - if ((s)->directory->auth > (a)) \ - return -EPERM; \ - } while(0) - -#endif
--- a/sys/include/cpu.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -#ifndef __CPU_H -#define __CPU_H - -static inline u64 getcpuid() -{ - u64 cpuid = ~0; - - asm("stidp 0(%1)\n" - : /* output */ - "=m" (cpuid) - : /* input */ - "a" (&cpuid) - ); - - return cpuid; -} - -static inline u16 getcpuaddr() -{ - u16 cpuaddr = ~0; - - asm("stap 0(%1)\n" - : /* output */ - "=m" (cpuaddr) - : /* input */ - "a" (&cpuaddr) - ); - - return cpuaddr; -} - -#endif
--- a/sys/include/dat.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ -#ifndef __DAT_H -#define __DAT_H - -struct address_space { - struct dat_rte *region_table; - struct dat_ste *segment_table; -}; - -/* region/segment-table destination */ -struct dat_td { - u64 origin:52, /* region/segment table origin */ - __reserved0:2, - g:1, /* subspace-group control */ - p:1, /* private-space control */ - s:1, /* storage-alteration-event ctl */ - x:1, /* space-switch-event control */ - r:1, /* real-space control */ - __reserved1:1, - dt:2, /* designation-type control */ - tl:2; /* table length */ -} __attribute__((packed)); - -#define DAT_TD_DT_RFT 3 /* region-first */ -#define DAT_TD_DT_RST 2 /* region-second */ -#define DAT_TD_DT_RTT 1 /* region-third */ -#define DAT_TD_DT_ST 0 /* segment */ - -/* region-table entries (first, second, and third) */ -struct dat_rte { - u64 origin:52, /* next-level-table origin */ - __reserved0:4, - tf:2, /* table offset (next lower tbl) */ - i:1, /* region invalid */ - __reserved1:1, - tt:2, /* table-type bits (current tbl) */ - tl:2; /* table length (next lower tbl) */ -} __attribute__((packed)); - -/* - * Constants for struct rte - */ -#define DAT_RTE_TT_RFT 3 /* region-first */ -#define DAT_RTE_TT_RST 2 /* region-second */ -#define DAT_RTE_TT_RTT 1 /* region-third */ - -#define ADDR_TO_RTE_ORIGIN(a) ((a) >> 12) -#define RTE_ORIGIN_TO_ADDR(o) ((void*)(((u64)(o)) << 12)) - -/* segment-table entries */ -struct dat_ste { - u64 origin:53, /* page-table origin */ - __reserved0:1, - p:1, /* page-protection bit */ - __reserved1:3, - i:1, /* segment-invalid bit */ - c:1, /* common-segment bit */ - tt:2, /* table-type bits */ - __reserved2:2; -} __attribute__((packed)); - -#define DAT_STE_TT_ST 0 /* segment-table */ - -#define ADDR_TO_STE_ORIGIN(a) ((a) >> 11) -#define STE_ORIGIN_TO_ADDR(o) ((void*)(((u64)(o)) << 11)) - -/* page-table entries */ -struct dat_pte { - u64 pfra:52, /* page-frame real address */ - __zero0:1, - i:1, /* page-invalid bit */ - p:1, /* page-protection bit */ - __zero1:1, - __reserved:8; -} __attribute__((packed)); - -#define DAT_RX(addr) (((u64)(addr)) >> 31) -#define DAT_SX(addr) ((((u64)(addr)) >> 20) & 0x7ff) -#define DAT_PX(addr) ((((u64)(addr)) >> 12) & 0xff) -#define DAT_BX(addr) (((u64)(addr))& 0xfff) - -extern int dat_insert_page(struct address_space *as, u64 phy, u64 virt); -extern void setup_dat(void); -extern void load_as(struct address_space *as); - -extern int virt2phy(struct address_space *as, u64 virt, u64 *phy); - -static inline void store_pasce(u64 *pasce) -{ - asm volatile( - " stctg 1,1,0(%0)\n" - : /* output */ - : /* input */ - "a" (pasce) - ); -} - -static inline void load_pasce(u64 pasce) -{ - if (!pasce) - return; - - asm volatile( - " lctlg 1,1,%0\n" - : /* output */ - : /* input */ - "m" (pasce) - ); -} - -/* get host real address from guest real, using the currently loaded ASCE */ -static inline int virt2phy_current(u64 virt, u64 *phy) -{ - u64 result; - int cc; - - asm volatile( - " lrag %0,0(%%r0,%2)\n" - " ipm %1\n" - " srl %1,28\n" - : /* output */ - "=d" (result), - "=d" (cc) - : /* input */ - "a" (virt) - : /* clobber */ - "cc" - ); - - if (cc != 0) - return -EFAULT; - - *phy = result; - return 0; -} - -#endif
--- a/sys/include/device.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -#ifndef __DEVICE_H -#define __DEVICE_H - -#include <atomic.h> -#include <spinlock.h> -#include <list.h> - -struct device; -struct irb; - -struct device_type { - struct list_head types; - int (*reg)(struct device *dev); - int (*interrupt)(struct device *dev, struct irb *irb); - void* (*enable)(struct device *dev); - int (*snprintf)(struct device *dev, char *buf, int len); - - /* the following ops are for the bdev wrapper layer */ - int (*read)(struct device *dev, u8 *buf, int len); - - u16 type; - u8 model; - u8 all_models; -}; - -struct device { - struct list_head devices; - u32 sch; /* subchannel id */ - u16 type; /* 3330, 3215, ... */ - u8 model; - u16 ccuu; /* device number */ - struct device_type *dev; - - spinlock_t q_lock; - struct io_op *q_cur; - struct list_head q_out; - atomic_t attention; - - atomic_t in_use; /* is the device in use by someone? */ - - atomic_t refcnt; /* internal reference counter */ - - union { - struct { - u16 cyls; /* cylinders */ - u16 tracks; /* tracks per cylinder */ - u16 len; /* track length */ - u16 recs; /* number of records */ - u8 sectors; /* # sectors per track */ - u8 formula; /* capacity formula */ - u16 f1, /* factor f1 */ - f2, /* factor f2 */ - f3, /* factor f3 */ - f4, /* factor f4 */ - f5; /* factor f5 */ - } eckd; - struct { - u16 blk_size; /* block size */ - u32 bpg; /* blocks per cyclical group */ - u32 bpp; /* blocks per access possition */ - u32 blks; /* blocks */ - } fba; - }; -}; - -extern struct device *find_device_by_type(u16 type, u8 model); -extern struct device *find_device_by_ccuu(u16 ccuu); -extern struct device *find_device_by_sch(u32 sch); -extern int register_device_type(struct device_type *dev); -extern void scan_devices(void); -extern void list_devices(struct console *con, - void (*f)(struct console*, struct device*)); -extern void register_drivers(void); - -static inline void dev_get(struct device *dev) -{ - BUG_ON(atomic_read(&dev->refcnt) < 1); - atomic_inc(&dev->refcnt); -} - -static inline void dev_put(struct device *dev) -{ - atomic_dec(&dev->refcnt); - BUG_ON(atomic_read(&dev->refcnt) < 1); -} - -/* device specific register functions */ -extern int register_driver_3215(void); -extern int register_driver_dasd(void); - -#endif
--- a/sys/include/directory.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -#ifndef __DIRECTORY_H -#define __DIRECTORY_H - -#include <console.h> - -enum directory_vdevtype { - VDEV_INVAL = 0, /* invalid */ - VDEV_CONS, /* a console */ - VDEV_DED, /* dedicated real device */ - VDEV_SPOOL, /* backed by the spool */ - VDEV_MDISK, /* a minidisk */ - VDEV_LINK, /* a link to another user's device */ -}; - -struct directory_vdev { - enum directory_vdevtype type; /* device type */ - u16 vdev; /* virtual dev # */ - - union { - /* VDEV_CONS */ - struct { - } console; - - /* VDEV_DED */ - struct { - u16 rdev; /* real device # */ - } dedicate; - - /* VDEV_SPOOL */ - struct { - u16 type; - u8 model; - } spool; - - /* VDEV_MDISK */ - struct { - u16 cyloff; /* first cylinder # */ - u16 cylcnt; /* cylinder count */ - u16 rdev; /* real DASD containing the mdisk */ - } mdisk; - - /* VDEV_LINK */ - struct { - } link; - } u; -}; - -struct user { - char *userid; - struct task *task; - - /* VM configuration */ - u64 storage_size; - - struct directory_vdev *devices; - - u8 auth; -}; - -extern struct user *find_user_by_id(char *userid); - -#endif
--- a/sys/include/disassm.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -#ifndef __DISASSM_H -#define __DISASSM_H - -enum inst_fmt { - IF_INV = 0, - IF_VAR, - IF_E, - IF_I, - IF_RI1, - IF_RI2, - IF_RIE, - IF_RIL1, - IF_RIL2, - IF_RIS, - IF_RR, - IF_RR_MASK, - IF_RRE, - IF_RRF1, - IF_RRF2, - IF_RRF3, - IF_RRR, - IF_RRS, - IF_RS1, - IF_RS2, - IF_RSI, - IF_RSL, - IF_RSY1, - IF_RSY2, - IF_RX, - IF_RX_MASK, - IF_RXE, - IF_RXF, - IF_RXY, - IF_S, - IF_SI, - IF_SIL, - IF_SIY, - IF_SS1, - IF_SS2, - IF_SS3, - IF_SS4, - IF_SS5, - IF_SSE, - IF_SSF, - IF_DIAG, -}; - -struct disassm_instruction { - union { - char *name; /* instruction name; inst only */ - - void *ptr; /* next level table; table only */ - } u; - - /* all */ - char fmt; /* instruction format */ - - /* table only */ - char len; /* table len */ - char loc; /* sub-opcode location offset in bits */ -}; - -#define DA_INST(idx,ifmt,iname) [idx] = { .fmt = IF_##ifmt, .u.name = #iname, } -#define DA_INST_TBL(idx,itbl,ilen,iloc) [idx] = { .fmt = IF_VAR, .u.ptr = (itbl), \ - .len = (ilen), .loc = (iloc), } - -extern int disassm(u8 *bytes, char *buf, int buflen); - -#endif
--- a/sys/include/ebcdic.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -#ifndef __EBCDIC_H -#define __EBCDIC_H - -extern u8 ascii2ebcdic_table[256]; -extern u8 ebcdic2ascii_table[256]; - -/* - * Generic translate buffer function. - */ -static inline void __translate(u8 *buf, int len, const u8 *table) -{ - asm volatile( - " sgr %%r0,%%r0\n" /* test byte = 0 */ - " la %%r2,0(%0)\n" /* buffer */ - " lgr %%r3,%2\n" /* length */ - " la %%r4,0(%1)\n" /* table */ - "0: tre %%r2,%%r4\n" - " brc 1,0b\n" - : /* output */ - : /* input */ - "a" (buf), - "a" (table), - "d" (len) - : /* clobbered */ - "cc", "r0", "r2", "r3", "r4" - ); -} - -#define ascii2ebcdic(buf, len) \ - __translate((buf), (len), ascii2ebcdic_table) -#define ebcdic2ascii(buf, len) \ - __translate((buf), (len), ebcdic2ascii_table) - -#endif
--- a/sys/include/edf.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -#ifndef __EDF_H -#define __EDF_H - -#include <mutex.h> -#include <device.h> - -struct ADT { - u32 ADTIDENT; /* VOL START / LABEL IDENTIFIER */ -#define __ADTIDENT 0xC3D4E2F1 /* 'CMS1' in EBCDIC */ - u8 ADTID[6]; /* VOL START / VOL IDENTIFIER */ - u8 ADTVER[2]; /* VERSION LEVEL */ - u32 ADTDBSIZ; /* DISK BLOCK SIZE */ - u32 ADTDOP; /* DISK ORIGIN POINTER */ - u32 ADTCYL; /* NUM OF FORMATTED CYL ON DISK */ - u32 ADTMCYL; /* MAX NUM FORMATTED CYL ON DISK */ - u32 ADTNUM; /* Number of Blocks on disk */ - u32 ADTUSED; /* Number of Blocks used */ - u32 ADTFSTSZ; /* SIZE OF FST */ - u32 ADTNFST; /* NUMBER OF FST'S PER BLOCK */ - u8 ADTDCRED[6]; /* DISK CREATION DATE (YYMMDDHHMMSS) */ - u8 ADTFLGL; /* LABEL FLAG BYTE (ADTFLGL) */ -#define ADTCNTRY 0x01 /* Century for disk creation date (0=19, 1=20), - * corresponds to ADTDCRED. */ - u8 reserved[1]; - u32 ADTOFFST; /* DISK OFFSET WHEN RESERVED */ - u32 ADTAMNB; /* ALLOC MAP BLOCK WITH NEXT HOLE */ - u32 ADTAMND; /* DISP INTO HBLK DATA OF NEXT HOLE */ - u32 ADTAMUP; /* DISP INTO USER PART OF ALLOC MAP */ - u32 ADTOFCNT; /* Count of SFS open files for this ADT */ - u8 ADTSFNAM[8]; /* NAME OF SHARED SEGMENT */ -}; - -struct FST { - u8 FSTFNAME[8]; /* filename */ - u8 FSTFTYPE[8]; /* filetype */ - u8 FSTDATEW[2]; /* DATE LAST WRITTEN - MMDD */ - u8 FSTTIMEW[2]; /* TIME LAST WRITTEN - HHMM */ - u16 FSTWRPNT; /* WRITE POINTER - ITEM NUMBER */ - u16 FSTRDPNT; /* READ POINTER - ITEM NUMBER */ - u8 FSTFMODE[2]; /* FILE MODE - LETTER AND NUMBER */ - u16 FSTRECCT; /* NUMBER OF LOGICAL RECORDS */ - u16 FSTFCLPT; /* FIRST CHAIN LINK POINTER */ - u8 FSTRECFM; /* F*1 - RECORD FORMAT - F OR V */ -#define FSTDFIX 0xC6 /* Fixed record format (EBCDIC 'F') */ -#define FSTDVAR 0xE5 /* Variable record format (EBCDIC 'V') */ - u8 FSTFLAGS; /* F*2 - FST FLAG BYTE */ -#define FSTRWDSK 0x80 /* READ/WRITE DISK */ -#define FSTRODSK 0x00 /* READ/ONLY DISK */ -#define FSTDSFS 0x10 /* Shared File FST */ -#define FSTXRDSK 0x40 /* EXTENSION OF R/O DISK */ -#define FSTXWDSK 0xC0 /* EXTENSION OF R/W DISK */ -#define FSTEPL 0x20 /* EXTENDED PLIST */ -#define FSTDIA 0x40 /* ITEM AVAILABLE */ -#define FSTDRA 0x01 /* PREVIOUS RECORD NULL */ -#define FSTCNTRY 0x08 /* Century for date last written (0=19, 1=20),\\ - corresponds to FSTYEARW, FSTADATI. */ -#define FSTACTRD 0x04 /* ACTIVE FOR READING */ -#define FSTACTWR 0x02 /* ACTIVE FOR WRITING */ -#define FSTACTPT 0x01 /* ACTIVE FROM A POINT */ -#define FSTFILEA 0x07 /* THE FILE IS ACTIVE */ - u32 FSTLRECL; /* LOGICAL RECORD LENGTH */ - u16 FSTBLKCT; /* NUMBER OF 800 BYTE BLOCKS */ - u16 FSTYEARW; /* YEAR LAST WRITTEN */ - u32 FSTFOP; /* ALT. FILE ORIGIN POINTER */ - u32 FSTADBC; /* ALT. NUMBER OF DATA BLOCKS */ - u32 FSTAIC; /* ALT. ITEM COUNT */ - u8 FSTNLVL; /* NUMBER OF POINTER BLOCK LEVELS */ - u8 FSTPTRSZ; /* LENGTH OF A POINTER ELEMENT */ - u8 FSTADATI[6]; /* ALT. DATE/TIME(YY MM DD HH MM SS) */ - u8 FSTREALM; /* Real filemode */ - u8 FSTFLAG2; /* F*3 - FST FLAG BYTE 2 FSTFLAG2 */ -#define FSTPIPEU 0x10 /* Reserved for CMS PIPELINES usage */ - u8 reserved[2]; -}; - -#define EDF_LABEL_BLOCK_NO 3 - -#define EDF_SUPPORTED_BLOCK_SIZE 4096 - -struct fs { - struct ADT ADT; - struct list_head files; - mutex_t lock; - struct device *dev; - void *tmp_buf; -}; - -struct file { - struct FST FST; - struct list_head files; - mutex_t lock; - struct fs *fs; - char *buf; -}; - -extern struct fs *edf_mount(struct device *dev); -extern struct file *edf_lookup(struct fs *fs, char *fn, char *ft); -extern int edf_read_rec(struct file *file, char *buf, u32 recno); - -#endif
--- a/sys/include/interrupt.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -#ifndef __INTERRUPT_H -#define __INTERRUPT_H - -/* - * I/O interruptions specific constants & structures - */ -struct io_int_code { - u32 ssid; - u32 param; -} __attribute__((packed)); - -#define PSA_INT_GPR ((u64*) 0x200) -#define PSA_TMP_PSW ((struct psw*) 0x280) - -#define IO_INT_OLD_PSW ((void*) 0x170) -#define IO_INT_NEW_PSW ((void*) 0x1f0) -#define IO_INT_CODE ((struct io_int_code*) 0xb8) - -#define EXT_INT_OLD_PSW ((void*) 0x130) -#define EXT_INT_NEW_PSW ((void*) 0x1b0) -#define EXT_INT_CODE ((u16*) 0x86) - -#define SVC_INT_OLD_PSW ((void*) 0x140) -#define SVC_INT_NEW_PSW ((void*) 0x1c0) -#define SVC_INT_CODE ((u16*) 0x8a) - -#define PGM_INT_OLD_PSW ((void*) 0x150) -#define PGM_INT_NEW_PSW ((void*) 0x1d0) -#define PGM_INT_ILC ((u8*) 0x8d) -#define PGM_INT_CODE ((u16*) 0x8e) - -/* - * Assembly stubs to call the C-handlers - */ -extern void IO_INT(void); -extern void EXT_INT(void); -extern void SVC_INT(void); -extern void PGM_INT(void); - -/** - * local_int_disable - disable interruptions & return old mask - */ -#define local_int_disable() ({ \ - unsigned long __flags; \ - __asm__ __volatile__ ( \ - "stnsm 0(%1),0xfc" : "=m" (__flags) : "a" (&__flags) ); \ - __flags; \ - }) - -/** - * local_int_restore - restore interrupt mask - * x: mask to restore - */ -#define local_int_restore(x) \ - __asm__ __volatile__("ssm 0(%0)" : : "a" (&x), "m" (x) : "memory") - -/** - * local_int_restore - restore interrupt mask - * x: mask to restore - */ -static inline int interruptable() -{ - u8 x; - - __asm__ __volatile__( - "stosm 0(%0),0x00" - : /* out */ - : /* in */ - "a" (&x), - "m" (x) - : /* clobber */ - "memory" - ); - - return (x & 0x43) != 0; -} - -extern void set_timer(void); - -/* - * The Supervisor-Service call table - */ -#define SVC_SCHEDULE 0 -#define SVC_SCHEDULE_BLOCKED 1 -#define NR_SVC 2 -extern u64 svc_table[NR_SVC]; - -/* Interrupt handlers */ -extern void __pgm_int_handler(void); -extern void __ext_int_handler(void); -extern void __io_int_handler(void); - -/* Interrupt handler stack pointer */ -extern u8 *int_stack_ptr; - -#endif
--- a/sys/include/io.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -#ifndef __IO_H -#define __IO_H - -#include <channel.h> -#include <atomic.h> -#include <list.h> - -struct device; - -/* - * Defines an I/O operation - * - * This structure contains any and all state one should need to service any - * I/O interruption. - */ -struct io_op { - struct orb orb; /* Operation Request Block */ - - struct list_head list; /* list of in-flight operations */ - - int (*handler)(struct device *dev, struct io_op *ioop, struct irb *irb); - /* I/O specific callback */ - void (*dtor)(struct device *dev, struct io_op *ioop); - /* I/O specific destructor */ - - int err; /* return code */ - atomic_t done; /* has the operation completed */ -}; - -extern void init_io(void); -extern int submit_io(struct device *dev, struct io_op *oop, int flags); - -#endif
--- a/sys/include/list.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,421 +0,0 @@ -/* - * Based on list.h from Linux Kernel - */ - -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H - -#define LIST_POISON1 ((void*) 0x8585858585858585ULL) -#define LIST_POISON2 ((void*) 0x8686868686868686ULL) - -/* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -static inline void INIT_LIST_HEAD(struct list_head *list) -{ - list->next = list; - list->prev = list; -} - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - prev->next = next; -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty() on entry does not return true after this, the entry is - * in an undefined state. - */ -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; -} - -/** - * list_replace - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * If @old was empty, it will be overwritten. - */ -static inline void list_replace(struct list_head *old, - struct list_head *new) -{ - new->next = old->next; - new->next->prev = new; - new->prev = old->prev; - new->prev->next = new; -} - -static inline void list_replace_init(struct list_head *old, - struct list_head *new) -{ - list_replace(old, new); - INIT_LIST_HEAD(old); -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_is_last - tests whether @list is the last entry in list @head - * @list: the entry to test - * @head: the head of the list - */ -static inline int list_is_last(const struct list_head *list, - const struct list_head *head) -{ - return list->next == head; -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -/** - * list_empty_careful - tests whether a list is empty and not being modified - * @head: the list to test - * - * Description: - * tests whether a list is empty _and_ checks that no other CPU might be - * in the process of modifying either member (next or prev) - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - */ -static inline int list_empty_careful(const struct list_head *head) -{ - struct list_head *next = head->next; - return (next == head) && (next == head->prev); -} - -static inline void __list_splice(struct list_head *list, - struct list_head *head) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - struct list_head *at = head->next; - - first->prev = head; - head->next = first; - - last->next = at; - at->prev = last; -} - -/** - * list_splice - join two lists - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(struct list_head *list, struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head); - INIT_LIST_HEAD(list); - } -} - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_first_entry - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next; prefetch(pos->next), pos != (head); \ - pos = pos->next) - -/** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - * - * This variant differs from list_for_each() in that it's the - * simplest possible list iteration code, no prefetching is done. - * Use this for code that knows the list to be very short (empty - * or 1 entry) most of the time. - */ -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ - pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_struct within the struct. - * - * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_from - iterate over list of given type from the current point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing from current position. - */ -#define list_for_each_entry_from(pos, head, member) \ - for (; prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_continue - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing after current point, - * safe against removal of list entry. - */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_from - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type from current point, safe against - * removal of list entry. - */ -#define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_reverse - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate backwards over list of given type, safe against removal - * of list entry. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) - -#endif
--- a/sys/include/magic.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -#ifndef __MAGIC_H -#define __MAGIC_H - -#define MAGIC_PSW_IDLE_CODE 0x1D1E - -#define SLAB_MAGIC 0xe2d3c1c2 -#define SLAB_CONT_MAGIC 0xe2d3c1c3 - -#endif
--- a/sys/include/mm.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -#ifndef __MM_H -#define __MM_H - -extern u64 memsize; - -/* Turn Low-address protection on */ -static inline void lap_on(void) -{ - u64 cr0; - - asm volatile( - "stctg 0,0,%0\n" /* get cr0 */ - "oi %1,0x10\n" /* enable */ - "lctlg 0,0,%0\n" /* reload cr0 */ - : /* output */ - : /* input */ - "m" (cr0), - "m" (*(u64*) (((u8*)&cr0) + 4)) - ); -} - -#endif
--- a/sys/include/mutex.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -#ifndef __MUTEX_H -#define __MUTEX_H - -#include <list.h> -#include <atomic.h> -#include <spinlock.h> -#include <sched.h> -#include <interrupt.h> - -typedef struct { - atomic_t state; - spinlock_t queue_lock; - struct list_head queue; -} mutex_t; - -#define UNLOCKED_MUTEX(name) mutex_t name = { \ - .state = ATOMIC_INIT(1), \ - .queue = LIST_HEAD_INIT(name.queue), \ - .queue_lock = SPIN_LOCK_UNLOCKED, \ - } - -static inline void mutex_init(mutex_t *lock) -{ - atomic_set(&lock->state, 1); - INIT_LIST_HEAD(&lock->queue); - lock->queue_lock = SPIN_LOCK_UNLOCKED; -} - -extern void __mutex_lock(mutex_t *lock); - -static inline void mutex_lock(mutex_t *lock) -{ - /* - * if we are not interruptable, we shouldn't call any functions that - * may sleep - e.g., mutex_lock - */ - BUG_ON(!interruptable()); - - if (unlikely(atomic_add_unless(&lock->state, -1, 0) == 0)) - __mutex_lock(lock); /* the slow-path */ -} - -static inline void mutex_unlock(mutex_t *lock) -{ - struct task *task; - - spin_lock(&lock->queue_lock); - - if (likely(list_empty(&lock->queue))) { - /* no one is waiting on the queue */ - atomic_inc(&lock->state); - spin_unlock(&lock->queue_lock); - return; - } - - /* - * someone is waiting on the queue, let's dequeue them & make them - * runnable again - */ - task = list_first_entry(&lock->queue, struct task, blocked_list); - list_del(&task->blocked_list); - spin_unlock(&lock->queue_lock); - - make_runnable(task); -} - -#endif
--- a/sys/include/nucleus.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -#ifndef __NUCLEUS_H -#define __NUCLEUS_H - -#include <config.h> -#include <compiler.h> -#include <errno.h> -#include <string.h> - -extern volatile u64 ticks; - -extern struct datetime ipltime; - -/* The beginning of it all... */ -extern void start(u64 __memsize, u32 __iplsch); - -/* borrowed from Linux */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -/* borrowed from Linux */ -#define offsetof(type, member) __builtin_offsetof(type,member) - -static inline void lpswe(void *psw) -{ - asm volatile( - " lpswe 0(%0)\n" - : /* output */ - : /* input */ - "a" (psw) - : /* clobbered */ - "cc" - ); -} - -#define BUG() do { \ - asm volatile(".byte 0x00,0x00" : : : "memory"); \ - } while(0) -#define BUG_ON(cond) do { \ - if (unlikely(cond)) \ - BUG(); \ - } while(0) - -/* - * This should be as simple as a cast, but unfortunately, the BUG_ON check - * is there to make sure we never submit a truncated address to the channels - * - * In the future, the io code should check if IDA is necessary, and in that - * case allocate an IDAL & set the IDA ccw flag. Other parts of the system - * that require 31-bit address should do whatever their equivalent action - * is. - */ -static inline u32 ADDR31(void *ptr) -{ - u64 ip = (u64) ptr; - - BUG_ON(ip & ~0x7fffffffull); - - return (u32) ip; -} - -/* - * stdio.h equivalents - */ -struct console; - -extern int vprintf(struct console *con, const char *fmt, va_list args) - __attribute__ ((format (printf, 2, 0))); -extern int con_printf(struct console *con, const char *fmt, ...) - __attribute__ ((format (printf, 2, 3))); - -/* - * stdarg.h equivalents - */ - -#endif
--- a/sys/include/page.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -#ifndef __PAGE_H -#define __PAGE_H - -#include <list.h> - -#define PAGE_SHIFT 12 -#define PAGE_SIZE (1<<PAGE_SHIFT) -#define PAGE_MASK (PAGE_SIZE-1) - -#define PAGE_INFO_BASE ((struct page*) 0x400000) - -#define ZONE_NORMAL 0 -#define ZONE_LOW 1 - -#define ZONE_NORMAL_MAX_ORDER (64-PAGE_SHIFT) -#define ZONE_LOW_MAX_ORDER (31-PAGE_SHIFT) - -/* - * This structure describes a page of memory - */ -struct page { - union { - struct list_head buddy; /* buddy allocator list */ - struct list_head guest; /* guest storage list */ - }; -}; - -/* - * Externs - */ -extern void init_pages(void); - -/* - * Static inlines - */ -static inline struct page *page_num_to_ptr(u64 pnum) -{ - struct page *base = PAGE_INFO_BASE; - - return &base[pnum]; -} - -static inline void *page_to_addr(struct page *page) -{ - u64 pagenum = (((u64) page) - ((u64) PAGE_INFO_BASE)) / sizeof(struct page); - - return (void*) (pagenum << PAGE_SHIFT); -} - -static inline struct page *addr_to_page(void *addr) -{ - struct page *base = PAGE_INFO_BASE; - - return &base[((u64) addr) >> PAGE_SHIFT]; -} - -static inline int IS_LOW_ZONE(struct page *page) -{ - return ((u64) page_to_addr(page)) < (2UL*1024*1024*1024); -} - -static inline int ZONE_TYPE(struct page *page) -{ - return IS_LOW_ZONE(page) ? ZONE_LOW : ZONE_NORMAL; -} - -#endif
--- a/sys/include/sched.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,203 +0,0 @@ -#ifndef __SCHED_H -#define __SCHED_H - -#include <list.h> -#include <page.h> -#include <dat.h> -#include <clock.h> -#include <interrupt.h> - -#define CAN_SLEEP 1 /* safe to sleep */ -#define CAN_LOOP 2 /* safe to busy-wait */ - -#define TASK_RUNNING 0 -#define TASK_SLEEPING 1 -#define TASK_LOCKED 2 - -#define STACK_FRAME_SIZE 160 - -#define SCHED_SLICE_MS 30 /* 30ms scheduler slice */ -#define SCHED_TICKS_PER_SLICE (HZ / SCHED_SLICE_MS) - -#define HZ 100 /* number of ticks per second */ - -struct psw { - u8 _zero0:1, - r:1, /* PER Mask (R) */ - _zero1:3, - t:1, /* DAT Mode (T) */ - io:1, /* I/O Mask (IO) */ - ex:1; /* External Mask (EX) */ - - u8 key:4, /* Key */ - _zero2:1, - m:1, /* Machine-Check Mask (M) */ - w:1, /* Wait State (W) */ - p:1; /* Problem State (P) */ - - u8 as:2, /* Address-Space Control (AS) */ - cc:2, /* Condition Code (CC) */ - prog_mask:4; /* Program Mask */ - - u8 _zero3:7, - ea:1; /* Extended Addressing (EA) */ - - u32 ba:1, /* Basic Addressing (BA) */ - _zero4:31; - - u64 ptr; -}; - -/* - * saved registers for guests - * - * NOTE: some registers are saved in the SIE control block! - */ -struct guest_regs { - u64 gpr[16]; - u32 ar[16]; - u64 fpr[64]; - u32 fpcr; -}; - -/* saved registers for CP tasks */ -struct regs { - struct psw psw; - u64 gpr[16]; - u64 cr1; -}; - -/* - * These states mirror those described in chapter 4 of SA22-7832-06 - */ -enum virt_cpustate { - GUEST_STOPPED = 0, - GUEST_OPERATING, - GUEST_LOAD, - GUEST_CHECKSTOP, -}; - -#include <sie.h> - -struct virt_cpu { - /* the SIE control block is picky about alignment */ - struct sie_cb sie_cb; - - struct guest_regs regs; - u64 cpuid; - - enum virt_cpustate state; -}; - -#define TASK_NAME_LEN 16 - -/* - * This structure describes a running process. - */ -struct task { - struct regs regs; /* saved registers */ - - struct list_head run_queue; /* runnable list */ - struct list_head proc_list; /* processes list */ - struct list_head blocked_list; /* blocked on mutex/etc. list */ - - u64 slice_end_time; /* end of slice time (ticks) */ - - struct virt_cpu *cpu; /* guest cpu */ - - int state; /* state */ - - char name[TASK_NAME_LEN+1]; /* task name */ -}; - -struct virt_sys { - struct task *task; /* the virtual CPU task */ - struct user *directory; /* the directory information */ - - struct console *con; /* the login console */ - int print_ts; /* print timestamps */ - - struct list_head guest_pages; /* list of guest pages */ - struct list_head virt_devs; /* list of guest virtual devs */ - struct list_head online_users; /* list of online users */ - - struct address_space as; /* the guest storage */ -}; - -extern void init_sched(void); /* initialize the scheduler */ -extern struct task* create_task(char *name, int (*f)(void*), void*); - /* create a new task */ -extern void __schedule(struct psw *, - int newstate); /* scheduler helper - use with caution */ -extern void __schedule_svc(void); -extern void __schedule_blocked_svc(void); - -extern void make_runnable(struct task *task); - -extern void list_tasks(struct console *con, - void (*f)(struct console *, struct task*)); - -/** - * current - the current task's task struct - */ -#define current extract_task() - -#define PSA_CURRENT ((struct task**) 0x290) - -/** - * extract_task - return the current task struct - */ -static inline struct task *extract_task(void) -{ - return *PSA_CURRENT; -} - -/** - * set_task_ptr - set the stack's task struct pointer - * @task: task struct pointer to be made current - */ -static inline void set_task_ptr(struct task *task) -{ - *PSA_CURRENT = task; -} - -/** - * schedule - used to explicitly yield the cpu - */ -static inline void schedule(void) -{ - /* - * if we are not interruptable, we shouldn't call any functions that - * may sleep - schedule() is guaranteed to sleep :) - */ - BUG_ON(!interruptable()); - - asm volatile( - " svc %0\n" - : /* output */ - : /* input */ - "i" (SVC_SCHEDULE) - ); -} - -/** - * schedule_blocked - used to explicitly yield the cpu without readding the - * task to the runnable queue - */ -static inline void schedule_blocked(void) -{ - /* - * if we are not interruptable, we shouldn't call any functions that - * may sleep - schedule() is guaranteed to sleep :) - */ - BUG_ON(!interruptable()); - - asm volatile( - " svc %0\n" - : /* output */ - : /* input */ - "i" (SVC_SCHEDULE_BLOCKED) - ); -} - -#endif
--- a/sys/include/sie.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -#ifndef __SIE_H -#define __SIE_H - -/* - * Taken from linux/arch/s390/include/asm/kvm_host.h - */ - -#include <atomic.h> - -/* - * Constants for sie_cb->cpuflags - */ -#define CPUSTAT_HOST 0x80000000 -#define CPUSTAT_WAIT 0x10000000 -#define CPUSTAT_ECALL_PEND 0x08000000 -#define CPUSTAT_STOP_INT 0x04000000 -#define CPUSTAT_IO_INT 0x02000000 -#define CPUSTAT_EXT_INT 0x01000000 -#define CPUSTAT_RUNNING 0x00800000 -#define CPUSTAT_RETAINED 0x00400000 -#define CPUSTAT_TIMING_SUB 0x00020000 -#define CPUSTAT_SIE_SUB 0x00010000 -#define CPUSTAT_RRF 0x00008000 -#define CPUSTAT_SLSV 0x00004000 -#define CPUSTAT_SLSR 0x00002000 -#define CPUSTAT_ZARCH 0x00000800 -#define CPUSTAT_MCDS 0x00000100 -#define CPUSTAT_SM 0x00000080 -#define CPUSTAT_G 0x00000008 -#define CPUSTAT_J 0x00000002 -#define CPUSTAT_P 0x00000001 - -struct sie_cb { - atomic_t cpuflags; /* 0x0000 */ - u32 prefix; /* 0x0004 */ - u8 reserved8[32]; /* 0x0008 */ - u64 cputm; /* 0x0028 */ - u64 ckc; /* 0x0030 */ - u64 epoch; /* 0x0038 */ - u8 reserved40[4]; /* 0x0040 */ -#define LCTL_CR0 0x8000 - u16 lctl; /* 0x0044 */ - s16 icpua; /* 0x0046 */ - u32 ictl; /* 0x0048 */ - u32 eca; /* 0x004c */ - u8 icptcode; /* 0x0050 */ - u8 reserved51; /* 0x0051 */ - u16 ihcpu; /* 0x0052 */ - u8 reserved54[2]; /* 0x0054 */ - u16 ipa; /* 0x0056 */ - u32 ipb; /* 0x0058 */ - u32 scaoh; /* 0x005c */ - u8 reserved60; /* 0x0060 */ - u8 ecb; /* 0x0061 */ - u8 reserved62[2]; /* 0x0062 */ - u32 scaol; /* 0x0064 */ - u8 reserved68[4]; /* 0x0068 */ - u32 todpr; /* 0x006c */ - u8 reserved70[16]; /* 0x0070 */ - u64 gmsor; /* 0x0080 */ - u64 gmslm; /* 0x0088 */ - struct psw gpsw; /* 0x0090 */ - u64 gg14; /* 0x00a0 */ - u64 gg15; /* 0x00a8 */ - u8 reservedb0[30]; /* 0x00b0 */ - u16 iprcc; /* 0x00ce */ - u8 reservedd0[48]; /* 0x00d0 */ - u64 gcr[16]; /* 0x0100 */ - u64 gbea; /* 0x0180 */ - u8 reserved188[120]; /* 0x0188 */ -} __attribute__((aligned(256),packed)); - -#define VCPU_ZARCH(vcpu) (atomic_read(&((vcpu)->sie_cb.cpuflags)) & CPUSTAT_ZARCH) - -#endif
--- a/sys/include/slab.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -#ifndef __SLAB_H -#define __SLAB_H - -#include <list.h> -#include <spinlock.h> -#include <page.h> - -struct slab { - u32 magic; /* magic */ - spinlock_t lock; /* lock to protect entire slab */ - struct list_head slab_pages; /* list of pages */ - struct slab *first; /* pointer to first slab page */ - u16 objsize; /* effective object size */ - u16 startoff; /* first object offset */ - u16 count; /* number of objects in this page */ - u16 used; /* number of used objects */ - u8 bitmap[0]; /* allocation bitmap */ -} __attribute__((packed)); - -extern int init_slab(void); - -extern struct slab *create_slab(u16 objsize, u8 align); -extern void free_slab(struct slab *slab); - -extern void *malloc(int size, int type); -extern void free(void *ptr); - -#endif
--- a/sys/include/spinlock.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -#ifndef __SPINLOCK_H -#define __SPINLOCK_H - -/* - * Heavily based on Linux's spinlock implementation - */ - -typedef struct { - volatile unsigned int lock; -} spinlock_t; - -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } - -static inline int __compare_and_swap(volatile unsigned int *lock, - unsigned int old, unsigned int new) -{ - asm volatile( - " cs %0,%3,%1" - : "=d" (old), "=Q" (*lock) - : "0" (old), "d" (new), "Q" (*lock) - : "cc", "memory" ); - return old; -} - -#define spin_is_locked(x) ((x)->lock != 0) - -#define SPIN_RETRY 1000 - -extern void __spin_lock_wait(spinlock_t *lp, unsigned int pc); -extern int __spin_trylock_retry(spinlock_t *lp, unsigned int pc); - -/** - * spin_lock - lock a spinlock - * @lock: lock to lock - */ -static inline void spin_lock(spinlock_t *lock) -{ - unsigned long pc = 1 | (unsigned long) __builtin_return_address(0); - - if (unlikely(__compare_and_swap(&lock->lock, 0, pc) != 0)) - __spin_lock_wait(lock, pc); -} - -/** - * spin_trylock - attempt to try to acquire a lock, but do not spin if - * acquisition would fail - * @lock: lock to lock - */ -static inline int spin_trylock(spinlock_t *lock) -{ - unsigned long pc = 1 | (unsigned long) __builtin_return_address(0); - - if (likely(__compare_and_swap(&lock->lock, 0, pc) == 0)) - return 1; - return __spin_trylock_retry(lock, pc); -} - -/** - * spin_unlock - unlock a lock - * @lock: lock to unlock - */ -static inline void spin_unlock(spinlock_t *lock) -{ - __compare_and_swap(&lock->lock, lock->lock, 0); -} - -extern void spin_lock_intsave(spinlock_t *lock, unsigned long *mask); -extern void spin_unlock_intrestore(spinlock_t *lock, unsigned long mask); - -static inline void spin_double_lock(spinlock_t *l1, spinlock_t *l2) -{ - if (l1 < l2) { - spin_lock(l1); - spin_lock(l2); - } else { - spin_lock(l2); - spin_lock(l1); - } -} - -static inline void spin_double_unlock(spinlock_t *l1, spinlock_t *l2) -{ - if (l1 < l2) { - spin_unlock(l2); - spin_unlock(l1); - } else { - spin_unlock(l1); - spin_unlock(l2); - } -} - -#endif
--- a/sys/include/splash.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -#ifndef __SPLASH_H -#define __SPLASH_H - -extern char *splash[]; - -#endif
--- a/sys/include/vcpu.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -#ifndef __VCPU_H -#define __VCPU_H - -#include <sched.h> - -/*****************************************************************************/ -/* Guest exception queuing */ - -enum PROG_EXCEPTION { - PROG_OPERAND = 0x0001, - PROG_PRIV = 0x0002, - PROG_EXEC = 0x0003, - PROG_PROT = 0x0004, - PROG_ADDR = 0x0005, - PROG_SPEC = 0x0006, - PROG_DATA = 0x0007, -}; - -extern void queue_prog_exception(struct virt_sys *sys, enum PROG_EXCEPTION type, u64 param); - -/*****************************************************************************/ -/* Guest register reading & address calculation */ - -static inline u64 __guest_gpr(struct virt_cpu *cpu, int gpr) -{ - u64 ret = cpu->regs.gpr[gpr]; - - if (!(atomic_read(&cpu->sie_cb.cpuflags) & CPUSTAT_ZARCH)) - ret &= 0xffffffffULL; - - return ret; -} - -static inline u64 __guest_addr(struct virt_cpu *cpu, u64 disp, int x, int b) -{ - u64 mask; - - if (cpu->sie_cb.gpsw.ea && cpu->sie_cb.gpsw.ba) - mask = ~0; - else if (!cpu->sie_cb.gpsw.ea && cpu->sie_cb.gpsw.ba) - mask = 0x7fffffff; - else if (!cpu->sie_cb.gpsw.ea && !cpu->sie_cb.gpsw.ba) - mask = 0x00ffffff; - else - BUG(); - - return (disp + - (x ? __guest_gpr(cpu, x) : 0) + - (b ? __guest_gpr(cpu, b) : 0)) & mask; -} - -/*****************************************************************************/ -/* SIE Interception Param parsing & instruction decode */ - -#define IP_TO_RAW(sie) ((((u64)(sie).ipa) << 32) | ((u64)(sie).ipb)) - -static inline u64 RAW_S_1(struct virt_cpu *cpu) -{ - u64 raw = IP_TO_RAW(cpu->sie_cb); - - return __guest_addr(cpu, - (raw >> 16) & 0xfff, - (raw) >> 28 & 0xf, - 0); -} - -#endif
--- a/sys/include/vdevice.h Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -#ifndef __VDEVICE_H -#define __VDEVICE_H - -#include <list.h> -#include <directory.h> -#include <sched.h> - -struct virt_device { - struct list_head devices; - enum directory_vdevtype vtype; /* VDEV_CONS, VDEV_DED, ... */ - u32 sch; /* subchannel id */ - u16 type; /* 3330, 3215, ... */ - u8 model; - - union { - struct { - struct device *rdev; - /* real device */ - } dedicate; - } u; - - struct pmcw pmcw; /* path info */ - struct scsw scsw; /* subchannel-status */ -}; - -extern int alloc_virt_dev(struct virt_sys *sys, - struct directory_vdev *dirdev, u32 sch); - -#endif
--- a/sys/mm/Makefile Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -objs-mm := buddy.o page.o slab.o dat.o
--- a/sys/mm/buddy.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,209 +0,0 @@ -/* - * Copyright (c) 2007 Josef 'Jeff' Sipek - */ - -#include <list.h> -#include <page.h> -#include <mm.h> -#include <buddy.h> -#include <spinlock.h> - -/* - * Lists of free page ranges - */ -static struct list_head orders_normal[64-PAGE_SHIFT]; -static struct list_head orders_low[31-PAGE_SHIFT]; - -static spinlock_t orders_lock = SPIN_LOCK_UNLOCKED; - -static void __init_buddy_alloc(u64 base, int pages, int max_order, - struct list_head *orders) -{ - int order; - struct page *p; - - for(order=0; order < max_order; order++) { - INIT_LIST_HEAD(&orders[order]); - - if (pages & (1 << order)) { - p = page_num_to_ptr(base >> PAGE_SHIFT); - - list_add(&p->buddy, &orders[order]); - - base += (PAGE_SIZE << order); - } - } -} - -/* - * Initialize the buddy allocator. This is rather simple, and the only - * complication is that we must keep track of storage below 2GB separately - * since some IO related structures can address only the first 2GB. *sigh* - */ -void init_buddy_alloc(u64 start) -{ - u64 normal_pages; - u64 low_pages; - - if (memsize > 2UL*1024*1024*1024) { - /* There are more than 2GB of storage */ - low_pages = (2UL*1024*1024*1024 - start) >> PAGE_SHIFT; - normal_pages = (memsize - start) >> PAGE_SHIFT; - normal_pages -= low_pages; - } else { - /* All the storage is under the 2GB mark */ - low_pages = (memsize - start) >> PAGE_SHIFT; - normal_pages = 0; - } - - /* let's add all the free low storage to the lists */ - __init_buddy_alloc(start, low_pages, ZONE_LOW_MAX_ORDER, orders_low); - - /* now, let's add all the free storage above 2GB */ - __init_buddy_alloc(2UL*1024*1024*1024, normal_pages, ZONE_NORMAL_MAX_ORDER, - orders_normal); -} - -static struct page *__do_alloc_pages(int order, struct list_head *orders) -{ - struct page *page; - - if (!list_empty(&orders[order])) { - page = list_first_entry(&orders[order], struct page, buddy); - - list_del(&page->buddy); - - return page; - } - - return NULL; -} - -static struct page *__alloc_pages(int order, int type) -{ - struct page *p; - - /* Do we have to use ZONE_LOW? */ - if (type == ZONE_LOW) - goto zone_low; - - p = __do_alloc_pages(order, orders_normal); - if (p) - return p; - - /* If there was no ZONE_NORMAL page, let's try ZONE_LOW */ - -zone_low: - return __do_alloc_pages(order, orders_low); -} - -/* - * Split a given (actual) order allocation into an allocation of wanted - * order, and return the rest of pages to the unused lists - * - * E.g., - * - * pages (base): - * - * +---+---+---+---+---+---+---+---+ - * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | - * +---+---+---+---+---+---+---+---+ - * - * actual = 3 - * wanted = 1 - * - * return order 2 range back to free pool: - * - * +---+---+---+---+ - * | 4 | 5 | 6 | 7 | - * +---+---+---+---+ - * - * return order 1 range back to free pool: - * - * +---+---+ - * | 2 | 3 | - * +---+---+ - * - * The End. Now, pages 2-7 are back in the free pool, and pages 0&1 are an - * order 1 allocation. - * - */ -static void __chip_pages(struct page *base, int actual, int wanted) -{ - struct page *p; - struct list_head *orders; - - orders = (IS_LOW_ZONE(base) ? orders_low : orders_normal); - - for(; actual > wanted; actual--) { - p = &base[1 << (actual-1)]; - list_add(&p->buddy, &orders[actual-1]); - } -} - -/** - * alloc_pages - allocate a series of consecutive pages - * @order: allocate 2^order consecutive pages - * @type: type of pages (<2GB, or anywhere) - */ -struct page *alloc_pages(int order, int type) -{ - struct page *page; - int gord; - unsigned long mask; - int max_order; - - spin_lock_intsave(&orders_lock, &mask); - - /* easy way */ - page = __alloc_pages(order, type); - if (page) - goto out; - - /* - * There is no page-range of the given order, let's try to find the - * smallest one larger and split it - */ - - max_order = (type == ZONE_LOW ? - ZONE_LOW_MAX_ORDER : ZONE_NORMAL_MAX_ORDER); - - for(gord=order+1; gord < max_order; gord++) { - if (gord >= max_order) - break; - - page = __alloc_pages(gord, type); - if (!page) - continue; - - __chip_pages(page, gord, order); - - goto out; - } - - /* alright, totally out of memory */ - page = NULL; - -out: - spin_unlock_intrestore(&orders_lock, mask); - - return page; -} - -void free_pages(void *ptr, int order) -{ - struct page *base = addr_to_page(ptr); - unsigned long mask; - struct list_head *orders; - - orders = IS_LOW_ZONE(base) ? orders_low : orders_normal; - - spin_lock_intsave(&orders_lock, &mask); - list_add(&base->buddy, &orders[order]); - spin_unlock_intrestore(&orders_lock, mask); - - /* - * TODO: a more complex thing we could try is to coallesce adjecent - * page ranges into one higher order one (defrag) - */ -}
--- a/sys/mm/dat.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -#include <page.h> -#include <buddy.h> -#include <dat.h> -#include <mm.h> - -static void *alloc_table(int order) -{ - struct page *p; - - p = alloc_pages(order, ZONE_NORMAL); - BUG_ON(!p); - memset(page_to_addr(p), 0xff, PAGE_SIZE << order); - - return page_to_addr(p); -} - -/** - * dat_insert_page - insert a virt->phy mapping into an address space - * @as: address space to add the mapping to - * @phy: physical address to add - * @virt: virtual address to add - */ -int dat_insert_page(struct address_space *as, u64 phy, u64 virt) -{ - struct dat_rte *region; - struct dat_ste *segment; - struct dat_pte *page; - void *ptr; - - region = as->region_table; - - if (!region) { - if (!as->segment_table) - /* - * Need to allocate the segment table - * - * max of 2048 * 8-byte entries = 16 kbytes - */ - as->segment_table = alloc_table(2); - - segment = as->segment_table; - - goto walk_segment; - } - - BUG_ON(DAT_RX(virt)); // FIXME: we don't support storage >2GB - - if (region->origin == 0xfffffffffffffUL) { - /* - * Need to allocate the segment table - * - * max of 2048 * 8-byte entries = 16 kbytes - */ - ptr = alloc_table(2); - - region->origin = ADDR_TO_RTE_ORIGIN((u64) ptr); - - region->tf = 0; /* FIXME: is this right? */ - region->i = 0; - region->tt = DAT_RTE_TT_RTT; - region->tl = 3; /* FIXME: is this right? */ - region->__reserved0 = 0; - region->__reserved1 = 0; - } - - segment = RTE_ORIGIN_TO_ADDR(region->origin); - -walk_segment: - segment += DAT_SX(virt); - - if (segment->origin == 0x1fffffffffffffUL) { - /* - * Need to allocate the page table - * - * max of 256 * 8-byte entries = 2048 bytes - */ - ptr = alloc_table(0); - - segment->origin = ADDR_TO_STE_ORIGIN((u64) ptr); - segment->p = 0; - segment->i = 0; - segment->c = 0; - segment->tt = DAT_STE_TT_ST; - segment->__reserved0 = 0; - segment->__reserved1 = 0; - segment->__reserved2 = 0; - } - - page = STE_ORIGIN_TO_ADDR(segment->origin); - page += DAT_PX(virt); - - page->pfra = phy >> PAGE_SHIFT; - page->i = 0; - page->p = 0; - page->__zero0 = 0; - page->__zero1 = 0; - page->__reserved = 0; - - return 0; -} - -void setup_dat(void) -{ - /* nothing to do! */ -} - -void load_as(struct address_space *as) -{ - struct dat_td cr1; - - BUG_ON(!as->segment_table); - - /* - * Load up the PASCE (cr1) - */ - memset(&cr1, 0, sizeof(struct dat_td)); - cr1.origin = ((u64)as->segment_table) >> 12; - cr1.dt = DAT_TD_DT_ST; - cr1.tl = 3; - - asm volatile( - " lctlg 1,1,%0\n" - : /* output */ - : /* input */ - "m" (cr1) - ); -}
--- a/sys/mm/page.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2007 Josef 'Jeff' Sipek - */ - -#include <list.h> -#include <page.h> -#include <mm.h> - -/* - * Main storage size - */ -u64 memsize; - -/* - * Initialize fields in a struct page - */ -static void __init_page(struct page *page) -{ - INIT_LIST_HEAD(&page->buddy); -} - -/* - * Initialize struct page for each available page - */ -void init_pages(void) -{ - u64 pnum; - - for(pnum=0; pnum < (memsize>>PAGE_SHIFT); pnum++) - __init_page(page_num_to_ptr(pnum)); -} -
--- a/sys/mm/slab.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,283 +0,0 @@ -/* - * Copyright (c) 2007 Josef 'Jeff' Sipek - */ - -#include <magic.h> -#include <buddy.h> -#include <slab.h> -#include <page.h> - -static struct slab *generic[7]; - -/* - * Create slab caches for 16, 32, 64, 128, and 256 byte allocations - */ -int init_slab(void) -{ - generic[0] = create_slab(16, 4); - if (!generic[0]) - goto out_err; - - generic[1] = create_slab(32, 4); - if (!generic[1]) - goto out_err; - - generic[2] = create_slab(64, 4); - if (!generic[2]) - goto out_err; - - generic[3] = create_slab(128, 4); - if (!generic[3]) - goto out_err; - - generic[4] = create_slab(256, 8); - if (!generic[4]) - goto out_err; - - generic[5] = create_slab(512, 8); - if (!generic[5]) - goto out_err; - - generic[6] = create_slab(1024, 8); - if (!generic[6]) - goto out_err; - - return 0; - -out_err: - free_slab(generic[0]); - free_slab(generic[1]); - free_slab(generic[2]); - free_slab(generic[3]); - free_slab(generic[4]); - free_slab(generic[5]); - free_slab(generic[6]); - - return -ENOMEM; -} - -/** - * create_slab - Create a new slab - * @objsize: object size in bytes - * @align: object alignment in bytes (must be a power of two) - */ -struct slab *create_slab(u16 objsize, u8 align) -{ - struct page *page; - struct slab *slab; - - if (!objsize || !align) - return NULL; - - page = alloc_pages(0, ZONE_NORMAL); - if (!page) - return NULL; - - slab = page_to_addr(page); - memset(slab, 0, PAGE_SIZE); - - slab->magic = SLAB_MAGIC; - slab->lock = SPIN_LOCK_UNLOCKED; - INIT_LIST_HEAD(&slab->slab_pages); - slab->first = slab; - - align--; /* turn into a mask */ - - /* actual object size */ - if (objsize & align) - objsize += align + 1 - (objsize & align); - slab->objsize = objsize; - - /* number of objects in a page */ - slab->count = 8 * (PAGE_SIZE - sizeof(struct slab)) / (8 * objsize + 1); - - /* offset of the first object */ - slab->startoff = sizeof(struct slab) + (slab->count + 4) / 8; - if (slab->startoff & align) { - u16 tmp; - - slab->startoff += align + 1 - (slab->startoff & align); - - /* - * TODO: there's got to be a better way to ensure that we - * fit into a single page - */ - tmp = slab->startoff + slab->count * slab->objsize; - if (tmp > PAGE_SIZE) - slab->count--; - } - - slab->used = 0; - - return slab; -} - -void free_slab(struct slab *passed_slab) -{ - struct slab *slab; - - if (!passed_slab) - return; - - BUG_ON(passed_slab->magic != SLAB_MAGIC); - BUG_ON(passed_slab->used != 0); - - list_for_each_entry(slab, &passed_slab->slab_pages, slab_pages) { - BUG_ON(slab->magic != SLAB_CONT_MAGIC); - BUG_ON(slab->used != 0); - - /* - * Theoretically, we should remove the page from the list, - * but no one _really_ cares - */ - - free_pages(slab, 0); - } - - free_pages(passed_slab, 0); -} - -static inline void *__alloc_slab_obj_newpage(struct slab *slab, int type) -{ - struct page *page; - struct slab *new; - - page = alloc_pages(0, type); - if (!page) - return ERR_PTR(-ENOMEM); - - new = page_to_addr(page); - - memset(new, 0, PAGE_SIZE); - new->magic = SLAB_CONT_MAGIC; - new->first = slab; - new->objsize = slab->objsize; - new->startoff = slab->startoff; - new->count = slab->count; - - /* add it to the current slab */ - list_add_tail(&new->slab_pages, &slab->slab_pages); - - return new; -} - -static void *alloc_slab_obj(struct slab *passed_slab, int type) -{ - struct slab *slab = passed_slab; - void *obj = NULL; - int objidx; - u8 *bits; - u8 mask; - unsigned long int_mask; - - if (!slab) - return NULL; - - BUG_ON(passed_slab->magic != SLAB_MAGIC); - - spin_lock_intsave(&passed_slab->lock, &int_mask); - - /* - * Does the first slab page have an unused object _AND_ is in the - * right zone? - */ - if (slab->used < slab->count && ZONE_TYPE(addr_to_page(slab)) == type) - goto alloc; - - /* - * No. Find the first slab page that has unused objects - */ - list_for_each_entry(slab, &passed_slab->slab_pages, slab_pages) - if (slab->used < slab->count && - ZONE_TYPE(addr_to_page(slab)) == type) - goto alloc; - - /* - * None of the pages have an unused object. Let's allocate another - * page - */ - - slab = __alloc_slab_obj_newpage(passed_slab, type); - if (IS_ERR(slab)) - /* - * FIXME: if we tried to get a ZONE_NORMAL and failed, - * shouldn't we retry with ZONE_LOW? - */ - goto out; - - -alloc: - /* found a page */ - for (objidx = 0; objidx < slab->count; objidx++) { - bits = slab->bitmap + (objidx/8); - - mask = 1 << (7 - (objidx % 8)); - - if (*bits & mask) - continue; - - slab->used++; - *bits |= mask; - - obj = ((u8*) slab) + slab->startoff + slab->objsize * objidx; - break; - } - -out: - spin_unlock_intrestore(&passed_slab->lock, int_mask); - - return obj; -} - -static void free_slab_obj(void *ptr) -{ - struct slab *slab; - int objidx; - u8 *bits; - unsigned long int_mask; - - /* get the slab object ptr */ - slab = (struct slab *) (((u64) ptr) & ~0xfff); - - spin_lock_intsave(&slab->first->lock, &int_mask); - - /* calculate the object number */ - objidx = (((u64) ptr) - ((u64) slab) - slab->startoff) / slab->objsize; - - /* update the bitmap */ - bits = slab->bitmap + (objidx/8); - *bits &= ~(1 << (7 - (objidx % 8))); - - if (--slab->used) { - /* FIXME: free the page? */ - } - - spin_unlock_intrestore(&slab->first->lock, int_mask); -} - -void *malloc(int size, int type) -{ - if (!size) - return NULL; - if (size <= 16) - return alloc_slab_obj(generic[0], type); - if (size <= 32) - return alloc_slab_obj(generic[1], type); - if (size <= 64) - return alloc_slab_obj(generic[2], type); - if (size <= 128) - return alloc_slab_obj(generic[3], type); - if (size <= 256) - return alloc_slab_obj(generic[4], type); - if (size <= 512) - return alloc_slab_obj(generic[5], type); - if (size <= 1024) - return alloc_slab_obj(generic[6], type); - return NULL; -} - -void free(void *ptr) -{ - if (ptr) - free_slab_obj(ptr); -}
--- a/sys/nucleus/Makefile Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -objs-nucleus := init.o io.o printf.o ebcdic.o int.o ext.o svc.o pgm.o \ - spinlock.o mutex.o sched.o
--- a/sys/nucleus/ebcdic.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -#include <ebcdic.h> - -/* - * Tables taken from Linux's arch/s390/kernel/ebcdic.c - */ - -/* - * ASCII (IBM PC 437) -> EBCDIC 037 - */ -u8 ascii2ebcdic_table[256] = -{ - /*00 NUL SOH STX ETX EOT ENQ ACK BEL */ - 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, - /*08 BS HT LF VT FF CR SO SI */ - /* ->NL */ - 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ - 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, - /*18 CAN EM SUB ESC FS GS RS US */ - /* ->IGS ->IRS ->IUS */ - 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F, - /*20 SP ! " # $ % & ' */ - 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, - /*28 ( ) * + , - . / */ - 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, - /*30 0 1 2 3 4 5 6 7 */ - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - /*38 8 9 : ; < = > ? */ - 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, - /*40 @ A B C D E F G */ - 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - /*48 H I J K L M N O */ - 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, - /*50 P Q R S T U V W */ - 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, - /*58 X Y Z [ \ ] ^ _ */ - 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D, - /*60 ` a b c d e f g */ - 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - /*68 h i j k l m n o */ - 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, - /*70 p q r s t u v w */ - 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - /*78 x y z { | } ~ DL */ - 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, - /*80*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*88*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*90*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*98*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*A0*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*A8*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*B0*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*B8*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*C0*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*C8*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*D0*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*D8*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*E0 sz */ - 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*E8*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*F0*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*F8*/ - 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF -}; - -/* - * EBCDIC 037 -> ASCII (IBM PC 437) - */ -u8 ebcdic2ascii_table[256] = -{ - /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */ - 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, - /* 0x08 -GE -SPS -RPT VT FF CR SO SI */ - 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC - -ENP ->LF */ - 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, - /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB - -IUS */ - 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC - -INP */ - 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, - /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL - -SW */ - 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, - /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */ - 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, - /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */ - 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, - /* 0x40 SP RSP ä ---- */ - 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, - /* 0x48 . < ( + | */ - 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, - /* 0x50 & ---- */ - 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, - /* 0x58 ß ! $ * ) ; */ - 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA, - /* 0x60 - / ---- Ä ---- ---- ---- */ - 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, - /* 0x68 ---- , % _ > ? */ - 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, - /* 0x70 ---- ---- ---- ---- ---- ---- ---- */ - 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - /* 0x78 * ` : # @ ' = " */ - 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, - /* 0x80 * a b c d e f g */ - 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - /* 0x88 h i ---- ---- ---- */ - 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, - /* 0x90 ° j k l m n o p */ - 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, - /* 0x98 q r ---- ---- */ - 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, - /* 0xA0 ~ s t u v w x */ - 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - /* 0xA8 y z ---- ---- ---- ---- */ - 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, - /* 0xB0 ^ ---- § ---- */ - 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, - /* 0xB8 ---- [ ] ---- ---- ---- ---- */ - 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07, - /* 0xC0 { A B C D E F G */ - 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - /* 0xC8 H I ---- ö ---- */ - 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, - /* 0xD0 } J K L M N O P */ - 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, - /* 0xD8 Q R ---- ü */ - 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, - /* 0xE0 \ S T U V W X */ - 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - /* 0xE8 Y Z ---- Ö ---- ---- ---- */ - 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, - /* 0xF0 0 1 2 3 4 5 6 7 */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - /* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */ - 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07 -}; -
--- a/sys/nucleus/ext.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -#include <interrupt.h> -#include <sched.h> - -/* - * This is the tick counter, it starts at 0 when we initialize the nucleus - */ -volatile u64 ticks; - -void set_timer(void) -{ - u64 time = 1000 * 1000 * CLK_MICROSEC / HZ; - - asm volatile( - "spt %0\n" /* set timer value */ - : /* output */ - : /* input */ - "m" (time) - ); -} - -void __ext_int_handler(void) -{ - if (*EXT_INT_CODE == 0x1005) { - /* - * This is the timer, let's call the scheduler. - */ - - ticks++; - - set_timer(); - - /* - * No need to save the registers, the assembly stub that - * called this function already saved them at PSA_INT_GPR - */ - if (!(ticks % SCHED_TICKS_PER_SLICE)) { - __schedule(EXT_INT_OLD_PSW, TASK_SLEEPING); - - /* unreachable */ - BUG(); - } - } -} -
--- a/sys/nucleus/init.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,204 +0,0 @@ -/* - * Copyright (c) 2007 Josef 'Jeff' Sipek - */ - -#include <mm.h> -#include <dat.h> -#include <slab.h> -#include <page.h> -#include <buddy.h> -#include <io.h> -#include <sched.h> -#include <device.h> -#include <console.h> -#include <interrupt.h> -#include <magic.h> -#include <cp.h> - -static struct psw new_io_psw = { - .ea = 1, - .ba = 1, - - .ptr = (u64) &IO_INT, -}; - -static struct psw new_ext_psw = { - .ea = 1, - .ba = 1, - - .ptr = (u64) &EXT_INT, -}; - -static struct psw new_svc_psw = { - .ea = 1, - .ba = 1, - - .ptr = (u64) &SVC_INT, -}; - -static struct psw new_pgm_psw = { - .ea = 1, - .ba = 1, - - .ptr = (u64) &PGM_INT, -}; - -u8 *int_stack_ptr; - -/* the time HVF got IPLd */ -struct datetime ipltime; - -static void init_int_stack(void) -{ - struct page *page; - - page = alloc_pages(0, ZONE_NORMAL); - BUG_ON(!page); - - int_stack_ptr = PAGE_SIZE + (u8*)page_to_addr(page); -} - -static void idle_task_body(void) -{ - /* - * Warning: hack alert! The following overrides what __init_task - * set, this allows us to skip the usual start_task wrapper. - */ - current->regs.psw.w = 1; - current->regs.psw.ptr = MAGIC_PSW_IDLE_CODE; - - /* - * Load the new PSW that'll wait with special magic code set - */ - lpswe(¤t->regs.psw); - - BUG(); -} - -/* - * This is where everything starts - */ -void start(u64 __memsize, u32 __iplsch) -{ - u64 first_free_page; - u64 struct_page_bytes; - struct psw psw; - struct console *opcon; /* operator's console */ - - /* - * ticks starts at 0 - */ - ticks = 0; - - /* - * save total system memory size - */ - memsize = __memsize; - - /* - * Initialize struct page entries - */ - init_pages(); - - /* - * Calculate address of the first free page (we may have to round - * up) - */ - struct_page_bytes = (memsize >> PAGE_SHIFT) * sizeof(struct page); - - first_free_page = (u64) PAGE_INFO_BASE + struct_page_bytes; - if (struct_page_bytes & (PAGE_SIZE-1)) - first_free_page += PAGE_SIZE - (struct_page_bytes & (PAGE_SIZE-1)); - - /* - * Initialize the buddy allocator - */ - init_buddy_alloc(first_free_page); - - /* - * Initialize slab allocator default caches - */ - init_slab(); - - /* - * Set up interrupt PSWs - */ - memcpy(IO_INT_NEW_PSW, &new_io_psw, sizeof(struct psw)); - memcpy(EXT_INT_NEW_PSW, &new_ext_psw, sizeof(struct psw)); - memcpy(SVC_INT_NEW_PSW, &new_svc_psw, sizeof(struct psw)); - memcpy(PGM_INT_NEW_PSW, &new_pgm_psw, sizeof(struct psw)); - - /* Turn on Low-address Protection */ - lap_on(); - - /* - * Set up page table entries for the nucleus - */ - setup_dat(); - - /* - * Allocate & initialize the interrupt stack - */ - init_int_stack(); - - /* - * Initialize the io subsystem - */ - init_io(); - - /* - * Register all the device drivers - */ - register_drivers(); - - /* - * Time to enable interrupts => load new psw - */ - memset(&psw, 0, sizeof(struct psw)); - psw.io = 1; - psw.ea = 1; - psw.ba = 1; - - asm volatile( - " larl %%r1,0f\n" - " stg %%r1,%0\n" - " lpswe %1\n" - "0:\n" - : /* output */ - "=m" (psw.ptr) - : /* input */ - "m" (psw) - : /* clobbered */ - "r1" - ); - - /* - * Let's discover all the devices attached - */ - scan_devices(); - - /* - * Initialize the process scheduler - */ - init_sched(); - - /* - * IPL is more or less done - */ - get_parsed_tod(&ipltime); - - opcon = start_oper_console(); - - 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_cp(opcon); - - /* - * THIS IS WHERE THE IDLE TASK BEGINS - */ - - idle_task_body(); -} -
--- a/sys/nucleus/int.S Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -.text - -#include <interrupt.h> - -# -# IO Interrupt -# - .align 4 -.globl IO_INT - .type IO_INT, @function -IO_INT: - # save regs - STMG %r0,%r15,0x200(%r0) - - # set up stack - LARL %r15, int_stack_ptr - LG %r15, 0(%r15) - AGHI %r15,-160 - - LARL %r14, __io_int_handler - BALR %r14, %r14 # call the real handler - - # restore regs - LMG %r0,%r15,0x200(%r0) - - LPSWE 0x170 # go back to what we interrupted - - -# -# External Interrupt -# - .align 4 -.globl EXT_INT - .type EXT_INT, @function -EXT_INT: - # save regs - STMG %r0,%r15,0x200(%r0) - - # set up stack - LARL %r15, int_stack_ptr - LG %r15, 0(%r15) - AGHI %r15,-160 - - LARL %r14, __ext_int_handler - BALR %r14, %r14 # call the real handler - - # - # NOTE: we may never return from the C-interrupt handler if the - # interrupt was caused by the timer clock, in which case the - # scheduler kicks in, and gives control to someone else - # - - # restore regs - LMG %r0,%r15,0x200(%r0) - - LPSWE 0x130 # go back to what we interrupted - - -# -# Supervisor-Call Interrupt -# - .align 4 -.globl SVC_INT - .type SVC_INT, @function -SVC_INT: - # save regs - STMG %r0,%r15,0x200(%r0) - - # set up stack - LARL %r15, int_stack_ptr - LG %r15, 0(%r15) - AGHI %r15,-160 - - # find the right handler - LARL %r14, svc_table # table address - LGH %r2, 0x8a # interruption code - SLL %r2, 3 - # byte offset into table - LG %r14, 0(%r2,%r14) # load value from table - - BALR %r14, %r14 # call the real handler - - # restore regs - LMG %r0,%r15,0x200(%r0) - - LPSWE 0x140 # go back to what we interrupted - - -# -# Program Interrupt -# - .align 4 -.globl PGM_INT - .type PGM_INT, @function -PGM_INT: - # save regs - STMG %r0,%r15,0x200(%r0) - - # set up stack - LARL %r15, int_stack_ptr - LG %r15, 0(%r15) - AGHI %r15,-160 - - LARL %r14, __pgm_int_handler - BALR %r14, %r14 # call the real handler - - # - # NOTE: we may never return from the C-interrupt handler - # - - # restore regs - LMG %r0,%r15,0x200(%r0) - - LPSWE 0x150 # go back to what we interrupted
--- a/sys/nucleus/io.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2007 Josef 'Jeff' Sipek - */ - -#include <channel.h> -#include <io.h> -#include <interrupt.h> -#include <device.h> -#include <sched.h> -#include <atomic.h> -#include <spinlock.h> -#include <buddy.h> -#include <sched.h> - -/* - * Helper function to make sure the io_op has everything set right - */ -static int __verify_io_op(struct io_op *ioop) -{ - // FIXME: check everything that makes sense to check - return 0; -} - -static void __reset_reserved_fields(struct io_op *ioop) -{ - ioop->orb.__zero1 = 0; - ioop->orb.__zero2 = 0; - - ioop->orb.__reserved1 = 0; - ioop->orb.__reserved2 = 0; - ioop->orb.__reserved3 = 0; - ioop->orb.__reserved4 = 0; - ioop->orb.__reserved5 = 0; - ioop->orb.__reserved6 = 0; -} - -/* NOTE: assumes dev->q_lock is held */ -static void __submit_io(struct device *dev) -{ - struct io_op *ioop; - int err; - - if (dev->q_cur) - return; - - if (list_empty(&dev->q_out)) - return; - - ioop = list_entry(dev->q_out.next, struct io_op, list); - - err = start_sch(dev->sch, &ioop->orb); - if (!err) { - list_del(&ioop->list); - dev->q_cur = ioop; - } else - ioop->err = err; -} - -/* - * Submit an I/O request to a subchannel, and set up everything needed to - * handle the operation - */ -int submit_io(struct device *dev, struct io_op *ioop, int flags) -{ - static atomic_t op_id_counter; - unsigned long intmask; - int err = -EBUSY; - - err = __verify_io_op(ioop); - if (err) - return 0; - - /* make sure all reserved fields have the right values */ - __reset_reserved_fields(ioop); - - ioop->err = 0; - ioop->orb.param = atomic_inc_return(&op_id_counter); - atomic_set(&ioop->done, 0); - - /* add it to the list of ops */ - spin_lock_intsave(&dev->q_lock, &intmask); - list_add_tail(&ioop->list, &dev->q_out); - - __submit_io(dev); /* try to submit an IO right now */ - spin_unlock_intrestore(&dev->q_lock, intmask); - - if (flags & CAN_LOOP) { - while(!atomic_read(&ioop->done)) - ; - } else if (flags & CAN_SLEEP) { - while(!atomic_read(&ioop->done)) - schedule(); - } - - return 0; -} - -/* - * Initialize the channel I/O subsystem - */ -void init_io(void) -{ - u64 cr6; - - /* enable all I/O interrupt classes */ - asm volatile( - "stctg 6,6,%0\n" /* get cr6 */ - "oi %1,0xff\n" /* enable all */ - "lctlg 6,6,%0\n" /* reload cr6 */ - : /* output */ - : /* input */ - "m" (cr6), - "m" (*(u64*) (((u8*)&cr6) + 4)) - ); -} - -static int default_io_handler(struct device *dev, struct io_op *ioop, struct irb *irb) -{ - ioop->err = -EAGAIN; - - /* Unit check? */ - if (irb->scsw.dev_status & 0x02) - ioop->err = -EUCHECK; /* FIXME: we should bail */ - - /* Device End is set, we're done */ - if (irb->scsw.dev_status & 0x04) - ioop->err = 0; - - return 0; -} - -static void __cpu_initiated_io(struct device *dev, struct io_op *ioop, struct irb *irb) -{ - unsigned long intmask; - - ioop->err = test_sch(dev->sch, irb); - - if (!ioop->err && ioop->handler) - ioop->handler(dev, ioop, irb); - else if (!ioop->err) - default_io_handler(dev, ioop, irb); - - /* - * We can do this, because the test_sch function sets ->err, and - * therefore regardless of ->handler being defined, ->err will have - * a reasonable value - */ - if (ioop->err == -EAGAIN) - return; /* leave handler registered */ - - /* ...and remove it form the list */ - spin_lock_intsave(&dev->q_lock, &intmask); - dev->q_cur = NULL; - - __submit_io(dev); /* try to submit another IO */ - spin_unlock_intrestore(&dev->q_lock, intmask); - - /* flag io_op as done... */ - atomic_set(&ioop->done, 1); - - /* call the destructor if there is one */ - if (ioop->dtor) - ioop->dtor(dev, ioop); -} - -static void __dev_initiated_io(struct device *dev, struct irb *irb) -{ -} - -/* - * I/O Interrupt handler (C portion) - */ -void __io_int_handler(void) -{ - unsigned long intmask; - struct io_op *ioop; - struct device *dev; - struct irb irb; - - dev = find_device_by_sch(IO_INT_CODE->ssid); - BUG_ON(IS_ERR(dev)); - - spin_lock_intsave(&dev->q_lock, &intmask); - ioop = dev->q_cur; - spin_unlock_intrestore(&dev->q_lock, intmask); - - if (ioop && ioop->orb.param == IO_INT_CODE->param && - dev->sch == IO_INT_CODE->ssid) { - /* - * CPU-initiated operation - */ - - __cpu_initiated_io(dev, ioop, &irb); - dev_put(dev); - return; - } - - /* - * device-initiated operation - */ - BUG_ON(test_sch(dev->sch, &irb)); - - atomic_inc(&dev->attention); - - if (dev->dev->interrupt) - dev->dev->interrupt(dev, &irb); - else - __dev_initiated_io(dev, &irb); - dev_put(dev); -}
--- a/sys/nucleus/mutex.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -#include <mutex.h> - -/* slow-path mutex locking */ -void __mutex_lock(mutex_t *lock) -{ - spin_lock(&lock->queue_lock); - - if (unlikely(atomic_add_unless(&lock->state, -1, 0))) { - spin_unlock(&lock->queue_lock); - return; /* aha! someone released it & it's ours now! */ - } - - list_add_tail(¤t->blocked_list, &lock->queue); - - spin_unlock(&lock->queue_lock); - - schedule_blocked(); -}
--- a/sys/nucleus/pgm.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -#include <interrupt.h> -#include <ebcdic.h> -#include <vsprintf.h> - -static char abend_msg_buf[1024]; - -/* - * All is lost! All hands abandon ship! - * - * Try to write out a message to a special buffer to help debugging, and - * then stop the CPU. - */ -static void abend(void) -{ - int ret; - - ret = snprintf(abend_msg_buf, 1024, - "ABEND %04x" - "PSW ILC %d" - "%016llx%016llx" - "GPR " - "%016llx%016llx%016llx%016llx" - "%016llx%016llx%016llx%016llx" - "%016llx%016llx%016llx%016llx" - "%016llx%016llx%016llx%016llx", - *PGM_INT_CODE, (*PGM_INT_ILC) >> 1, - *((u64*) PGM_INT_OLD_PSW), *(((u64*) PGM_INT_OLD_PSW)+1), - PSA_INT_GPR[0], PSA_INT_GPR[1], PSA_INT_GPR[2], PSA_INT_GPR[3], - PSA_INT_GPR[4], PSA_INT_GPR[5], PSA_INT_GPR[6], PSA_INT_GPR[7], - PSA_INT_GPR[8], PSA_INT_GPR[9], PSA_INT_GPR[10], PSA_INT_GPR[11], - PSA_INT_GPR[12], PSA_INT_GPR[13], PSA_INT_GPR[14], PSA_INT_GPR[15] - ); - - if (ret) - ascii2ebcdic((u8 *) abend_msg_buf, ret); - - /* - * halt the cpu - * - * NOTE: we don't care about not clobbering registers as when this - * code executes, the CPU will be stopped. - */ - asm volatile( - "LR %%r15, %0 # buffer pointer\n" - "SR %%r1, %%r1 # not used, but should be zero\n" - "SR %%r3, %%r3 # CPU Address\n" - "SIGP %%r1, %%r3, 0x05 # Signal, order 0x05\n" - : /* out */ - : /* in */ - "a" (abend_msg_buf) - ); - - /* - * If SIGP failed, loop forever - */ - for(;;); -} - -void __pgm_int_handler(void) -{ - abend(); -}
--- a/sys/nucleus/printf.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2007 Josef 'Jeff' Sipek - */ - -#include <channel.h> -#include <console.h> -#include <directory.h> -#include <ebcdic.h> -#include <slab.h> -#include <clock.h> -#include <sched.h> -#include <vsprintf.h> -#include <stdarg.h> - -int vprintf(struct console *con, const char *fmt, va_list args) -{ - struct datetime dt; - char buf[128]; - int off = 0; - int ret; - - if (!con->sys || (con->sys && con->sys->print_ts)) { - memset(&dt, 0, sizeof(dt)); - ret = get_parsed_tod(&dt); - off = snprintf(buf, 128, "%02d:%02d:%02d ", dt.th, dt.tm, - dt.ts); - } - - ret = vsnprintf(buf+off, 128-off, fmt, args); - if (ret) { - ascii2ebcdic((u8 *) buf, off+ret); - con_write(con, (u8 *) buf, off+ret); - } - - return ret; -} - -int con_printf(struct console *con, const char *fmt, ...) -{ - va_list args; - int r; - - va_start(args, fmt); - r = vprintf(con, fmt, args); - va_end(args); - - return r; -}
--- a/sys/nucleus/sched.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,292 +0,0 @@ -#include <sched.h> -#include <page.h> -#include <buddy.h> -#include <slab.h> -#include <magic.h> - -/* list of all runnable processes */ -static struct list_head runnable; - -/* list of all processes in the system */ -static struct list_head processes; - -/* idle task */ -static struct task idle_task; - -/** - * start_task - helper used to start the task's code - * @f: function to execute - */ -static void start_task(int (*f)(void*), void *data) -{ - /* - * Start executing the code - */ - if (f) - (*f)(data); - - /* - * Done, now, it's time to cleanup - * - * FIXME: - * - delete from processes list - * - free stack page - * - free struct - * - schedule - */ - BUG(); -} - -/** - * __init_task - helper to initialize the task structure - * @task: task struct to initialize - * @f: pointer to function to execute - * @stack: pointer to the page for stack - */ -static void __init_task(struct task *task, void *f, void *data, void *stack) -{ - memset(task, 0, sizeof(struct task)); - - task->regs.psw.io = 1; - task->regs.psw.ex = 1; - task->regs.psw.ea = 1; - task->regs.psw.ba = 1; - - /* code to execute */ - task->regs.psw.ptr = (u64) start_task; - - task->regs.gpr[2] = (u64) f; - task->regs.gpr[3] = (u64) data; - task->regs.gpr[15] = ((u64) stack) + PAGE_SIZE - STACK_FRAME_SIZE; - - task->state = TASK_SLEEPING; -} - -/** - * init_idle_task - initialize the idle task - * - * Since the initial thread of execution already has a stack, and the task - * struct is a global variable, all that is left for us to do is to - * associate the current stack with idle_task. - */ -static void init_idle_task(void) -{ - u64 stack; - - stack = ((u64) &stack) & ~(PAGE_SIZE-1); - - __init_task(&idle_task, NULL, NULL, (void*) stack); - set_task_ptr(&idle_task); - - /* - * NOTE: The idle task is _not_ supposed to be on either of the - * two process lists. - */ -} - -/** - * create_task - create a new task - * @name: name for the task - * @f: function pointer to where thread of execution should begin - * @data: arbitrary data to pass to the task - */ -struct task* create_task(char *name, int (*f)(void *), void *data) -{ - struct page *page; - struct task *task; - - /* - * Allocate a page for stack, and struct task itself - */ - page = alloc_pages(0, ZONE_NORMAL); - task = malloc(sizeof(struct task), ZONE_NORMAL); - if (!page || !task) - goto out; - - /* - * Set up task's state - */ - __init_task(task, f, data, page_to_addr(page)); - - strncpy(task->name, name, TASK_NAME_LEN); - - /* - * Add the task to the scheduler lists - */ - list_add_tail(&task->proc_list, &processes); - list_add_tail(&task->run_queue, &runnable); - - return task; - -out: - free(task); - free_pages(page_to_addr(page), 0); - - return ERR_PTR(-ENOMEM); -} - -/** - * __sched - core of the scheduler code. This decides which task to run - * next, and switches over to it - */ -static void __sched(int force_idle) -{ - struct task *next; - - /* - * If there are no runnable tasks, let's use the idle thread - */ - if (force_idle || list_empty(&runnable)) { - next = &idle_task; - goto run; - } - - next = list_first_entry(&runnable, struct task, run_queue); - BUG_ON(!next); - - /* - * Remove the new task from the run queue & mark it as running - */ - list_del(&next->run_queue); - next->state = TASK_RUNNING; - -run: - next->slice_end_time = (force_idle) ? force_idle : ticks + SCHED_TICKS_PER_SLICE; - - /* - * NOTE: Because we need to load the registers _BEFORE_ we issue - * lpswe, we have to place the new psw into PSA and use register 0 - */ - memcpy(PSA_TMP_PSW, &next->regs.psw, sizeof(struct psw)); - set_task_ptr(next); - - load_pasce(next->regs.cr1); - - /* - * Load the next task - * - * FIXME: fp? ar? cr? - */ - asm volatile( - "lmg %%r0,%%r15,%0\n" /* load gpr */ - "lpswe %1\n" /* load new psw */ - : /* output */ - : /* input */ - "m" (next->regs.gpr[0]), - "m" (*PSA_TMP_PSW) - ); - - /* unreachable */ - BUG(); -} - -/** - * schedule_preempted - called to switch tasks - */ -void __schedule(struct psw *old_psw, int newstate) -{ - struct task *prev; - int force_idle = 0; - - /* - * Save last process's state - */ - - prev = current; - BUG_ON(!prev); - - /* - * Save the registers (gpr, psw, ...) - * - * FIXME: fp? ar? cr? - */ - memcpy(prev->regs.gpr, PSA_INT_GPR, sizeof(u64)*16); - memcpy(&prev->regs.psw, old_psw, sizeof(struct psw)); - - /* - * Idle task doesn't get added back to the queue - */ - if (prev == &idle_task) - goto go; - - store_pasce(&prev->regs.cr1); - - /* - * Add back on the queue - */ - prev->state = newstate; - if (newstate != TASK_LOCKED) - list_add_tail(&prev->run_queue, &runnable); - - /* - * If the previous task didn't use it's full slice, force idle_task - * to take over. - */ - if (prev->slice_end_time >= (ticks + SCHED_TICKS_PER_SLICE)) - force_idle = prev->slice_end_time; - -go: - /* - * Run the rest of the scheduler that selects the next task and - * context switches - */ - __sched(force_idle); -} - -/** - * __schedule_svc - wrapper for the supervisor-service call handler - */ -void __schedule_svc(void) -{ - __schedule(SVC_INT_OLD_PSW, TASK_SLEEPING); -} - -/** - * __schedule_blocked__svc - wrapper for the supervisor-service call handler - */ -void __schedule_blocked_svc(void) -{ - __schedule(SVC_INT_OLD_PSW, TASK_LOCKED); -} - -/* - * Initialize the schduler, and all associated structures - */ -void init_sched(void) -{ - u64 cr0; - - INIT_LIST_HEAD(&runnable); - INIT_LIST_HEAD(&processes); - - init_idle_task(); - - /* enable cpu timer interrupt subclass */ - asm volatile( - "stctg 0,0,%0\n" /* get cr0 */ - "oi %1,0x04\n" /* enable cpu timer subclass */ - "ni %1,0x7f\n" /* disable clock comp */ - "lctlg 0,0,%0\n" /* reload cr0 */ - : /* output */ - : /* input */ - "m" (cr0), - "m" (*(((u8*)&cr0) + 6)) - ); - - set_timer(); -} - -void list_tasks(struct console *con, - void (*f)(struct console *, struct task*)) -{ - struct task *t; - - list_for_each_entry(t, &processes, proc_list) - f(con, t); -} - -void make_runnable(struct task *task) -{ - task->state = TASK_SLEEPING; - list_add_tail(&task->run_queue, &runnable); -}
--- a/sys/nucleus/spinlock.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -#include <interrupt.h> -#include <spinlock.h> - -void __spin_lock_wait(spinlock_t *lp, unsigned int pc) -{ - while (1) { - if (__compare_and_swap(&lp->lock, 0, pc) == 0) - return; - } -} - -int __spin_trylock_retry(spinlock_t *lp, unsigned int pc) -{ - int count = SPIN_RETRY; - - while (count-- > 0) - if (__compare_and_swap(&lp->lock, 0, pc) == 0) - return 1; - return 0; -} - -/** - * spin_lock_intsave - disable interrupts and lock - * @lock: lock to lock - * @mask: pointer to where interrupt mask will be stored - */ -void spin_lock_intsave(spinlock_t *lock, unsigned long *mask) -{ - *mask = local_int_disable(); - spin_lock(lock); -} - -/** - * spin_unlock_intrestore - unlock and restore interrupt flags flags - * @lock: lock to unlock - * @mask: mask to restore - */ -void spin_unlock_intrestore(spinlock_t *lock, unsigned long mask) -{ - spin_unlock(lock); - local_int_restore(mask); -} -
--- a/sys/nucleus/svc.c Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -#include <sched.h> -#include <interrupt.h> - -u64 svc_table[NR_SVC] = { - (u64) __schedule_svc, - (u64) __schedule_blocked_svc, -}; -
--- a/sys/scripts/Makefile.build Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -# -# Build a single directory (built-in.o) -# - -.PHONY: all - -.PRECIOUS: %.o - -include scripts/Makefile.commands - -override DIR := $(patsubst %/,%,$(DIR)) -include $(DIR)/Makefile - -OBJS := $(foreach obj,$(objs-$(DIR)),$(patsubst %,$(DIR)/%,$(obj))) - -all: $(DIR)/built-in.o - @echo -n - -%/built-in.o: $(OBJS) - $(call o-to-builtin,$(OBJS),$@) - -%.o: %.S - $(call s-to-o,$<,$@) - -%.s: %.c - $(call c-to-s,$<,$@) - -%.o: %.c - $(call c-to-o,$<,$@) - -cp/directory.c: cp/directory_structs.c - -cp/directory_structs.c: hvf.directory - $(call gendir,$<,$@)
--- a/sys/scripts/Makefile.commands Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -cmd-ar=$(AR) rc $(1) $(2) -cmd-c-to-o=$(CC) $(CFLAGS) $(NUCLEUSCFLAGS) -c -o $(2) $(1) -cmd-c-to-s=$(CC) $(CFLAGS) $(NUCLEUSCFLAGS) -S -o $(2) $(1) -cmd-s-to-o=$(AS) -m64 -o $(2) $(1) -cmd-o-to-builtin=$(LD) $(LDFLAGS) -r -o $(2) $(1) -cmd-link-hvf=$(LD) $(LDFLAGS) -T scripts/linker.script -o $(2) $(1) -cmd-link-ipl=$(LD) -melf64_s390 -T linker.script -o $(2) $(1) -cmd-objcopy-t=$(OBJCOPY) -O binary -j .text $(1) $(2) -cmd-objcopy-tdr=$(OBJCOPY) -O binary -j .text -j .data -j .rodata -j .rodata.str1.2 $(1) $(2) -cmd-genipl-rdr=bash scripts/gen_rdr_ccws.sh $(1) -cmd-genipl-tape=bash scripts/gen_tape_ipl_s.sh $(1) $(2) -cmd-concat=cat $(1) > $(2) -cmd-pad=bash scripts/pad.sh $(1) $(2) -cmd-clean=rm -f $(1) -cmd-rclean=rm -rf $(1) -cmd-cscope=cscope -R -b -cmd-gendir=bash scripts/gen-dir.sh $(1) $(2) - -ifeq ($V,1) -ar=$(cmd-ar) -c-to-o=$(cmd-c-to-o) -c-to-s=$(cmd-c-to-s) -c-to-o-ipl=$(cmd-c-to-o-ipl) -s-to-o=$(cmd-s-to-o) -o-to-builtin=$(cmd-o-to-builtin) -link-hvf=$(cmd-link-hvf) -link-ipl=$(cmd-link-ipl) -objcopy-t=$(cmd-objcopy-t) -objcopy-tdr=$(cmd-objcopy-tdr) -genipl-rdr=$(cmd-genipl-rdr) -genipl-tape=$(cmd-genipl-tape) -concat=$(cmd-concat) -pad=$(cmd-pad) -clean=$(cmd-clean) -rclean=$(cmd-rclean) -cscope=$(cmd-cscope) -gendir=$(cmd-gendir) -else -ar=@echo " [AR] $(1)"; $(cmd-ar) -c-to-o=@echo " [CC] $(2)"; $(cmd-c-to-o) -c-to-s=@echo " [CC] $(2)"; $(cmd-c-to-s) -c-to-o-ipl=@echo " [CC] $(2)"; $(cmd-c-to-o-ipl) -s-to-o=@echo " [AS] $(2)"; $(cmd-s-to-o) -o-to-builtin=@echo " [LD] $(2)"; $(cmd-o-to-builtin) -link-hvf=@echo " [LD] hvf"; $(cmd-link-hvf) -link-ipl=@echo " [LD] $2"; $(cmd-link-ipl) -objcopy-t=@echo " [OBJCOPY] $2"; $(cmd-objcopy-t) -objcopy-tdr=@echo " [OBJCOPY] $2"; $(cmd-objcopy-tdr) -genipl-rdr=@echo " [GENRDR] $1"; $(cmd-genipl-rdr) -genipl-tape=@echo " [GENTAPE] $2"; $(cmd-genipl-tape) -concat=@echo " [CONCAT] $2"; $(cmd-concat) -pad=@echo " [PAD] $1 (multiple of $2 bytes)"; $(cmd-pad) -clean=@echo " [CLEAN] $1"; $(cmd-clean) -rclean=@echo " [CLEAN] $1"; $(cmd-rclean) -cscope=@echo " [CSCOPE] cscope.out"; $(cmd-cscope) -gendir=@echo " [DIRECT] $1 -> $2"; $(cmd-gendir) -endif -
--- a/sys/scripts/extract-version.sh Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -#!/bin/sh - -v=`git describe 2> /dev/null` - -case "$v" in - "") - awk '/^VERSION=/ { print substr($0,9); exit; }' < Makefile - ;; - *) - echo "$v" - ;; -esac
--- a/sys/scripts/gen-dir.sh Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -#!/bin/sh - -if [ $# -ne 2 ]; then - echo "Usage: $0 <directory> <outfile>" >&2 - exit 1 -fi - -userid="" - -close_devlist() -{ -cat >> directory.devlist <<DONE - { /* END */ .type = VDEV_INVAL, }, -}; -DONE -echo " }," >> directory.userlist -} - -parse_line() -{ - case "$1" in - USER) - [ ! -z "$userid" ] && close_devlist - - echo "static struct directory_vdev __directory_$2[] = {" >> directory.devlist - echo " {" >> directory.userlist - echo " .userid = \"$2\"," >> directory.userlist - echo " .auth = '$3'," >> directory.userlist - echo " .devices = __directory_$2," >> directory.userlist - - userid="$2" - ;; - MACHINE) - ;; - STORAGE) - tmp=`echo $2 | sed -e 's/[KMG]//g'` - case "$2" in - *K) size="${tmp}ULL * 1024ULL" ;; - *M) size="${tmp}ULL * 1024ULL * 1024ULL" ;; - *G) size="${tmp}ULL * 1024ULL * 1024ULL * 1024ULL" ;; - *) size="$2ULL" ;; - esac - echo " .storage_size = $size," >> directory.userlist - ;; - CONSOLE) - echo " { /* CON */ .type = VDEV_CONS, .vdev = 0x$2, }," >> directory.devlist - ;; - SPOOL) - case "$4" in - READER) - echo " { /* RDR */ .type = VDEV_SPOOL, .vdev = 0x$2, .u.spool = { .type = 0x$3, .model = 1 }, }," >> directory.devlist - ;; - PUNCH) - echo " { /* PUN */ .type = VDEV_SPOOL, .vdev = 0x$2, .u.spool = { .type = 0x$3, .model = 1 }, }," >> directory.devlist - ;; - PRINT) - echo " { /* PRT */ .type = VDEV_SPOOL, .vdev = 0x$2, .u.spool = { .type = 0x$3, .model = 1 }, }," >> directory.devlist - ;; - esac - ;; - MDISK) - echo " { /* MDISK */ .type = VDEV_MDISK, .vdev = 0x$2, .u.mdisk = { .rdev = 0x$6, .cyloff = $4, .cylcnt = $5, }, }," >> directory.devlist - ;; - DEDICATE) - echo " { /* DED */ .type = VDEV_DED, .vdev = 0x$2, .u.dedicate = { .rdev = 0x$3, }, }," >> directory.devlist - ;; - *) - echo "Error near:" "$@" >&2 - exit 2 - ;; - esac -} - -open_userlist() -{ - echo "static struct user directory[] = {" > directory.userlist -} - -close_userlist() -{ -cat >> directory.userlist <<DONE - { /* END */ .userid = NULL, }, -}; -DONE -} - -rm -f directory.devlist -open_userlist -cat "$1" | while read line ; do - [ -z "$line" ] && continue - - parse_line $line -done -close_devlist -close_userlist - -cat directory.devlist directory.userlist > $2 - -rm -f directory.devlist directory.userlist
--- a/sys/scripts/gen-docs.sh Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -write_docs() -{ -cat "$1" | awk -v fmt="$2" ' -BEGIN{ - docdir = "doc/commands"; - - if (fmt == "txt") { - cmd_title_open = ""; - cmd_title_close = ""; - sec_hdr_open = ""; - sec_hdr_close = ""; - par_open = ""; - par_close = ""; - pre_open = ""; - pre_close = ""; - } else if (fmt == "html") { - cmd_title_open = "<h1>"; - cmd_title_close = "</h1>"; - sec_hdr_open = "<h2>"; - sec_hdr_close = "</h2>"; - par_open = "<p>"; - par_close = "</p>"; - pre_open = "<pre>"; - pre_close = "</pre>"; - } else { - printf "ERROR: unknown format \"%s\"\n", fmt; - exit; - } - - fname = ""; -} - -/^[/ ]\*!!! / { - # begin a new command - if (fname != "") - close(fname); - - name=""; - fname=""; - for(i=2; i<=NF; i+=1) { - name = name $i " "; - fname = fname $i "_"; - } - name = substr(name, 1, length(name)-1); - fname = docdir "/" fmt "/" substr(fname, 1, length(fname)-1) "." fmt; - - print "Writing out ", fname; - - print cmd_title_open > fname; - print name >> fname; - print cmd_title_close >> fname; -} - -/^[/ ]\*!! AUTH / { - # output an authorization block - print sec_hdr_open >> fname; - print "Authorization" >> fname; - print sec_hdr_close par_open >> fname; - print $3 >> fname; - printf par_close >> fname; -} - -/^[/ ]\*!! PURPOSE$/ { - # output purpose section header - print sec_hdr_open >> fname; - print "Purpose" >> fname; - print sec_hdr_close >> fname; -} - -/^[/ ]\*!! NOTES$/ { - # output notes section header - print sec_hdr_open >> fname; - print "Usage Notes" >> fname; - print sec_hdr_close >> fname; -} - -/^[/ ]\*!p / { - # preformated verbatim line - print pre_open substr($0, 6) pre_close >> fname; -} - -/^[/ ]\*! / { - # verbatim line - print substr($0, 5) >> fname; -} - -/^[/ ]\*!$/ { - # just make a new paragraph - print substr($0, 5) >> fname; -} -' -} - -mkdir -p doc/commands/txt -mkdir -p doc/commands/html - -for srcf in cp/cmd_*.c ; do - echo "Inspecting $srcf..." - write_docs $srcf txt - write_docs $srcf html -done
--- a/sys/scripts/linker.script Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -SECTIONS -{ - ENTRY(start) - . = 0x100000; - .text : { *(.text) } - .data : { *(.data) } - .bss : { *(.bss) } -}
--- a/sys/scripts/pad.sh Tue Dec 29 20:04:16 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -#!/bin/bash - -# pad <fname> <multiple> - -len=`stat -c %s "$1"` -dif=`expr $len % "$2"` - -if [ $dif -ne 0 ]; then - dif=`expr "$2" - $dif` - dd if=/dev/zero bs=1 count=$dif 2> /dev/null >> "$1" -fi