[BACK]Return to context.c CVS log [TXT][DIR] Up to [local] / prex-old / sys / arch / arm / arm

File: [local] / prex-old / sys / arch / arm / arm / context.c (download)

Revision 1.1, Tue Jun 3 09:38:45 2008 UTC (16 years ago) by nbrk
Branch point for: MAIN

Initial revision

/*-
 * Copyright (c) 2005, Kohsuke Ohtani
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the author nor the names of any co-contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * context.c - context management routines
 */

/*
 * The context consists of kernel/user mode registers, and
 * kernel stack. The user mode registers are always saved to the
 * kernel stack when processor enters kernel mode by H/W or S/W events.
 *
 * The user mode registers are located in the interrupt/trap frame
 * at the top of the kernel stack. Before the control returns to user
 * mode next time, these register value will be restored automatically.
 *
 * All thread owns its context to keep its execution state. The
 * scheduler will switch the context to change an active thread.
 */

#include <kernel.h>
#include <cpu.h>
#include <locore.h>

/*
 * Initialize specified context.
 * @ctx: context id (pointer)
 * @kstack: kernel stack for the context
 *
 * All thread will start at the trap return routine - syscall_ret().
 * In this time, the interrupt flag is enabled and I/O access
 * is disabled.
 */
void
context_init(context_t ctx, u_long kstack)
{
	struct kern_regs *k;
	struct cpu_regs *u;

	ctx->uregs = (struct cpu_regs *)(kstack - sizeof(struct cpu_regs));

	/* Initialize kernel mode registers */
	k = &ctx->kregs;
	k->lr = (u_long)syscall_ret;
	k->sp = (u_long)ctx->uregs;

	/* Reset minimum user mode registers */
	u = ctx->uregs;
	u->r0 = 0;
	u->r1 = 0x11111111;
	u->r2 = 0x22222222;
	u->r3 = 0x33333333;
	u->svc_sp = kstack;
	u->cpsr = PSR_APP_MODE;	/* FIQ/IRQ is enabled */
}

/*
 * Set data to the specific register stored in context.
 * @type: register type to be set
 * @val: register value to be set
 *
 * Note: When user mode program counter is set, all register
 * values except stack pointer are reset to default value.
 */
void
context_set(context_t ctx, int type, u_long val)
{
	struct kern_regs *k;
	struct cpu_regs *u;

	switch (type) {
	case CTX_UENTRY:	/* User mode program counter */
		u = ctx->uregs;
		u->cpsr = PSR_APP_MODE;	/* FIQ/IRQ is enabled */
		u->pc = u->lr = val;
		break;
	case CTX_USTACK:	/* User mode stack pointer */
		u = ctx->uregs;
		u->sp = val;
		break;
	case CTX_KENTRY:	/* Kernel mode program counter */
		k = &ctx->kregs;
		k->lr = (u_long)kernel_thread_entry;
		k->r4 = val;	/* Entry point */
		break;
	case CTX_KARG:		/* Kernel mode argument */
		k = &ctx->kregs;
		k->r5 = val;
		break;
	}
}

/*
 * Switch to new context
 *
 * Kernel mode registers and kernel stack pointer are switched to the
 * next context.
 *
 * We don't use x86 task switch mechanism to minimize the context space.
 * The system has only one TSS(task state segment), and the context
 * switching is done by changing the register value in this TSS. Processor
 * will reload them automatically when it enters to the kernel mode in
 * next time.
 *
 * It is assumed all interrupts are disabled by caller.
 *
 * TODO: FPU context is not switched as of now.
 */
void
context_switch(context_t prev, context_t next)
{
	cpu_switch(&prev->kregs, &next->kregs);
}

/*
 * Save user mode context to handle exceptions.
 * @exc: exception code passed to the exception handler
 *
 * Copy current user mode registers in the kernel stack to the user
 * mode stack. The user stack pointer is adjusted for this area.
 * So that the exception handler can get the register state of
 * the target thread.
 *
 * It builds arguments for the exception handler in the following
 * format.
 *
 *   void exception_handler(int exc, void *regs);
 */
void
context_save(context_t ctx, int exc)
{
	struct cpu_regs *cur, *sav;

	/* Copy current register context into user mode stack */
	cur = ctx->uregs;
	sav = (struct cpu_regs *)(cur->sp - sizeof(struct cpu_regs));
	memcpy(sav, cur, sizeof(struct cpu_regs));

	/* Setup arguments for exception handler */
	cur->sp = (u_long)sav;
	cur->r0 = exc;		/* Argument 1 */
	cur->r1 = (u_long)sav;	/* Argument 2 */
	cur->r2 = 0xdeadbeef;	/* Tag */
}

/*
 * Restore register context to return from the exception handler.
 * @regs: pointer to user mode register context.
 */
void
context_restore(context_t ctx, void *regs)
{
	struct cpu_regs *cur;

	/* Restore user mode context */
	cur = ctx->uregs;
	memcpy(cur, regs, sizeof(struct cpu_regs));

	/* Correct some registers for fail safe */
	cur->cpsr = PSR_APP_MODE;
}