view cp/guest/reset.c @ 618:535aec703236

cp: define a FIXME macro that leaves a sclp message There are far too many fixmes in the code. Sadly, the compiler simply discards them. This usually isn't an issue until one accidentally hits a "weird" bug which just turns out to be an unhandled (but documented) case in another part of the code. Using a macro instead of a comment will let the compiler string-ify the text, and then at runtime use SCLP to print it out. This will immediatelly point at problem areas. So, keep an eye on SCLP from now on :) Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Tue, 13 Dec 2011 22:20:50 -0500
parents 4510b22eea5a
children
line wrap: on
line source

/*
 * (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 <vcpu.h>
#include <vdevice.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->cpu;

	if (flags & RESET_CPU) {
		if (flags & SET_ESA390) {
			FIXME("set the arch mode to ESA/390");
		}

		FIXME("clear interruptions (PROG, SVC, local EXT, MCHECK)");
		/*
		 * 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) {
		FIXME("if RESET_PLO_LOCKS_PRESERVE is set, don't reset 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)
{
	struct virt_device *vdev;
	int i;

	if (flags & RESET_FLOATING_INTERRUPTIONS) {
	}

	if (flags & RESET_IO) {
		for_each_vdev(sys, vdev) {
			FIXME("wait for I/O to complete?");
			mutex_lock(&vdev->lock);

			/* set to zero */
			vdev->pmcw.interrupt_param = 0;
			vdev->pmcw.isc = 0;
			vdev->pmcw.e = 0;
			vdev->pmcw.lm = 0;
			vdev->pmcw.mm = 0;
			vdev->pmcw.d = 0;
			vdev->pmcw.pnom = 0;
			vdev->pmcw.lpum = 0;
			vdev->pmcw.mbi = 0;
			vdev->pmcw.f = 0;
			vdev->pmcw.x = 0;
			vdev->pmcw.s = 0;

			/* set to one */
			vdev->pmcw.pom = 0xff;

			/* defined by the install - HVF hardcoded */
			vdev->pmcw.t = 0;
			vdev->pmcw.lpm = 0x80;
			vdev->pmcw.pim = 0x80;
			vdev->pmcw.pam = 0x80;
			for(i=0; i<8; i++)
				vdev->pmcw.chpid[i] = 0;

			memset(&vdev->scsw, 0, sizeof(struct scsw));
			mutex_unlock(&vdev->lock);
		}
	}
}

/**************/

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);
}