/****************************************************************************/
/*	Copyright (c) 2009, Bendor Research Pty. Ltd. All rights reserved.		*/
/*	This software is released under the GNU General Public License, version	*/
/*	3, with the exemptions that 1) the header files installed by this 	 	*/
/*	package can be included in closed-source code and 2) the libraries		*/
/*	built by this package can be statically linked into a closed-source 	*/
/*	binary. See the file LICENSE for the details.							*/
/*	This software is provided "AS IS", without any warranty or guarantee.	*/
/*	By using this software you acknowledge that neither Bendor Research nor	*/
/*	any of its personnel or affiliates can be held liable for any damages,	*/
/*	including, but not limited to, loss of business, loss of money, loss of */
/*	life, loss of reputation, arising out of this software being faulty or	*/
/*	not performing as advertised, even if Bendor Research was aware of such	*/
/*	faults in the software. You use this software at your own risk, any and */
/*	all liabilities that arise out of your using this software are strictly	*/
/*	yours.																	*/
/****************************************************************************/

#include "kernel.h"

/****************************************************************************/
/*				Kernel internally visible public data						*/
/****************************************************************************/

BX_STAT	_bx_state;					// Kernel state descriptor structure

/****************************************************************************/
/*							Local data										*/
/****************************************************************************/

/*
*	The ready queue is treated as a waitable resource. Therefore, it has
*	an associated policy. This structure is the policy that the ready queue
*	has. Since processes are never added or removed by the priority inheritance
*	mechanism to a waiting queue and the ready queue has no owner process, the
*	only function it must define is the 'chg' function, that is, the function
*	that is called when a process already on the queue has to change its
*	effective priority.
*/

static const struct _bx_poli rdyf = {

	.ins = NULL,
	.del = NULL,
	.chg = _bx_ProcRequeue,
	.add = NULL,
	.rem = NULL,
	.mut = NULL
};

/****************************************************************************/
/*					Public API functions									*/
/****************************************************************************/

/** @addtogroup bx_init */
/** @{ */

/**
*	Initialise the kernel.
*
*	This function must be called when the processor is in IRQ mode.
*	Both IRQ and FIQ should be disabled. The IRQ stack must be valid and
*	will be used for interrupts in the future.
*
*	The kernel is initialised and parametrised by a structure. The
*	following fields are defined:
*	- \p eq_length<br>is the length of the event queue. To keep the interrupt
*		latency as low as possible, when the kernel is doing something that
*		can take some time, such as evaluating the priority inheritance
*		chain, it does it while the interrupt is enabled. Therefore, if
*		an interrupt occurs and calls a kernel function, to keep the system
*		in a consistent state and to keep the kernel calls ordered, the
*		kernel call from the interrupt does not actually perform its
*		operation but places it into the event queue. When the kernel finishes
*		the time-consuming procedure, it will the run through the event queue
*		and execute the operations queued on it. This structure field is the
*		length of the event queue in number of events it can hold. The longer
*		the queue, the less likely that the kernel will need to hold off
*		interrupts. The event queue must be at least three times as long as the
*		maximum number of kernel calls any single interrupt handler can call.
*		It is suggested that you use an event queue that is at least 20 events
*		long, longer if you have interrupt routines that call several kernel
*		functions before returning.
*
*	- \p eq_wmark<br>is the watermark level for the event queue. When the kernel
*		is queueing events (due to it running some time consuming operation),
*		interrupts deposit their kernel calls in the queue. In order to avoid
*		the queue to overflow, when the number of events in the queue reaches
*		the watermark, the kernel disables furter interrupts. When, then due
*		to processing the events in the queue, the queue length drops below
*		the watermark, it enables them again. The watermark level should be
*		such that it leaves at least twice the maximum number of kernel calls
*		a single interrupt routine can cause. The watermark should not be
*		higher than the length of the event queue length minus 5 and should
*		not be less than 5. In general setting it to about 2/3 of the event
*		queue length is a good policy.
*
*	- \p eq_buff<br>is a pointer to an \p int array. The size of the array must be
*		3 times the length of the queue (a single queue entry occupies 3 32-bit
*		words). The array must be in RAM, of course.
*
*	- \p irq_handler<br>is a function pointer, the function having the prototype
*		of \p void \p func( \p void \p ); This function is your interrupt
*		handler. Since interrupt handling is dependent on what micrcocontroller
*		you use (they have different interrupt controllers), it is up to you
*		to write your interrupt handler. This function is a normal C function.
*		Do <b>not</b> give it an interrupt attribute. The interrupt prologue
*		and epilogue is done by the kernel. The function will run with the
*		processor being in interrupt mode (therefore using the interrupt stack).
*		It should be noted that since this function is just a normal C
*		function, it can be either a THUMB function or an ARM function.
*
*	- \p idle_state<br>is a function pointer, with the same signature as
*		\p irq_handler. Whenever the kernel has nothing to do, i.e. all
*		processes are sleeping, it will call this function. This function
*		is called with IRQ disabled, running in the kernel's internal context.
*		This function must return as soon as an interrupt becomes pending
*		(even if it is not yet accepted by the CPU core).
*		The best use of this function is to put the core into sleep mode to
*		save power. If you don't want to do anything while the kernel is
*		idle, you can give a \p NULL pointer here. Note that if you establish
*		an \p idle_state handler and that function does not return, the system
*		will stop. In addition, any attempt to call any kernel function from
*		the idle handler will crash the system.
*
*	- \p init_func<br>is a function pointer. This will be the first process that
*		the kernel starts. In fact, the call to BX_Init() will never return
*		and control will be passed to the \p init_func function. When the
*		function enters, it will have the highest priority and it will have
*		its protection level set to BX_PROT_FIQD, that is, neither IRQs nor
*		FIQs are accepted. Consequently, this function is protected from
*		everything, it can safely start other processes, initialise resources
*		and so on. Then it can drop its priority and lower its protection level
*		and become a normal process. As all processes, the function will run
*		in system mode (0x1f), that is, user mode with privileges.
*
*	- \p init_desc<br>is pointer to a BX_PROC structure (in RAM). That will be
*		the process descriptor for the \p init_func process.
*
*	- \p init_stack<br>is a word aligned pointer to the bottom of the stack
*		allocated for the init_proc process. It is defined as an \p unsigned
*		\p int pointer, to force the word alignment. If you want to allocate
*		1KB stack for the init process, then you would declare an \p unsigned
*		\p int array of 256 elements and set this structure field to the
*		value of \p array_name + 256, that is just behind the last element
*		of the array.
*
*	- \p kern_stack<br>is a word aligned pointer to the bottom of the stack
*		allocated for the kernel itself. It is defined the same way as
*		\p init_stack. This will be the satck that is used while the kernel
*		performs some internal work or when it is executing a delayed or user
*		initiated (soft) interrupt routine (i.e. it's working on the event
*		queue). It is suggested that you allocate at least 1KB of kernel stack.
*
*	@param	init	Pointer to a BX_INIT structure that contains the
*					information about the kernel's parameters.
*
*	@attention
*		This function does not return. It will pass the control to the
*		function denoted by the \p init_func parameter.
*
*	@par Example boot code
*		This is the assembly code that contains your vector table.
*	@include exec-init.S
*		This is the C file that contains your system boot code and
*		your first process (thread).
*	@include exec-init.c
*/

void	BX_Init( const BX_INIT *init )
{
BX_STAT	*stat = &_bx_state;
BX_PROC	*proc;
int		cpsr;

	// Prepare the process descriptor for the init process

	if ( (int) init->init_func & 1 )

		cpsr = ARM_STATE_SYS | ARM_IRQDI_MASK | ARM_FIQDI_MASK | ARM_THUMB_MASK;
	else
		cpsr = ARM_STATE_SYS | ARM_IRQDI_MASK | ARM_FIQDI_MASK;

	proc = init->init_desc;

	proc->type = BX_TYPE_PROC;
	proc->epri = BX_PRIO_MAX;
	proc->next = NULL;
	proc->prev = NULL;
	proc->wait = &stat->rdyq;
	proc->head = NULL;
	proc->tail = NULL;
	proc->rpri = BX_PRIO_MAX;
	proc->prot = BX_PROT_FIQD;
	proc->sigs = 0;
	proc->mask = 0;
	proc->cntx[ BX_CNTX_SP ] = (int) init->init_stack & ~7;
	proc->cntx[ BX_CNTX_LR ] = (int) _bx_ProcExit;
	proc->cntx[ BX_CNTX_PC ] = (int) init->init_func;
	proc->cntx[ BX_CNTX_PS ] = cpsr;

	// Initialise the kernel state structure

	stat->exec[ BX_EXEC_OLD ] = (int) proc->cntx;
	stat->exec[ BX_EXEC_NEW ] = (int) proc->cntx;
	stat->exec[ BX_EXEC_ISR ] = (int) init->uirq_func;
	stat->exec[ BX_EXEC_STK ] = (int) init->kern_stack & ~7;
	stat->exec[ BX_EXEC_MOD ] = BX_MODE_USR;
	stat->exec[ BX_EXEC_LEN ] = 0;

	stat->rdyq.head = proc;
	stat->rdyq.tail = proc;
	stat->rdyq.ftab = (struct _bx_poli *) &rdyf;
	stat->idle = init->idle_func;
	stat->eget = 0;
	stat->eput = 0;
	stat->elen = init->evtq_size;
	stat->ewtm = init->evtq_wmrk;
	stat->evts = (BX_EVNT *) init->evtq_buff;
	stat->secs = 0;
	stat->usec = 0;
	stat->tlk1 = 0;
	stat->tlk2 = 0;
	stat->tacc = 0;
	stat->tqhd = NULL;
	stat->tqtl = NULL;

	// Now we have to load the new context

	TRACE_INIT();
	_bx_ProcLoad( proc->cntx );
}

/** @} */


