Subversion Repositories shark

Rev

Rev 2 | Rev 38 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Project: S.Ha.R.K.
 *
 * Coordinators:
 *   Giorgio Buttazzo    <giorgio@sssup.it>
 *   Paolo Gai           <pj@gandalf.sssup.it>
 *
 * Authors     :
 *   Paolo Gai           <pj@gandalf.sssup.it>
 *   (see the web pages for full authors list)
 *
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
 *
 * http://www.sssup.it
 * http://retis.sssup.it
 * http://shark.sssup.it
 */


/**
 ------------
 CVS :        $Id: init.c,v 1.1.1.1 2002-03-29 14:12:51 pj Exp $

 File:        $File$
 Revision:    $Revision: 1.1.1.1 $
 Last update: $Date: 2002-03-29 14:12:51 $
 ------------

 Kernel module registration and miscellaneous functions

 This file contains:

 level_alloc_descriptor
 resource_alloc_descriptor
 __compute_args__
 __call_main__
 sys_atinit
 sys_atexit

**/


/*
 * Copyright (C) 2000 Paolo Gai
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */


#include <stdarg.h>
#include <ll/ll.h>
#include <ll/stdlib.h>
#include <ll/stdio.h>
#include <ll/string.h>
#include <kernel/config.h>
#include <kernel/model.h>
#include <kernel/const.h>
#include <sys/types.h>
#include <kernel/types.h>
#include <kernel/descr.h>
#include <errno.h>
#include <kernel/var.h>
#include <kernel/func.h>

/*+ List of function to call at each rnlevel;
    they are posted with sys_atrunlevel +*/

static struct exit_func {
    void (*f)(void *);
    void *arg;
    int no_at_abort;
    int next;
} runlevel_list[MAX_RUNLEVEL_FUNC];

static int runlevel_init_list;
static int runlevel_init_tail;
static int runlevel_shutdown_list;
static int runlevel_before_list;
static int runlevel_after_list;
static int runlevel_free;


void runlevel_init()
{
  int i;

  for (i = 0; i < MAX_RUNLEVEL_FUNC-1; i++)
    runlevel_list[i].next = i+1;
  runlevel_list[MAX_RUNLEVEL_FUNC-1].next = -1;

  runlevel_init_list     = -1;
  runlevel_init_tail     = -1;
  runlevel_shutdown_list = -1;
  runlevel_before_list   = -1;
  runlevel_after_list    = -1;
  runlevel_free          = 0;
}

/*+ flags may be RUNLEVEL_XXX...
    aborting may be 0 or NO_AT_ABORT +*/

void call_runlevel_func(int runlevel, int aborting)
{
  int i, j;

  switch (runlevel) {
    case RUNLEVEL_INIT:
      i = runlevel_init_list;
      runlevel_init_list = -1;
      break;
    case RUNLEVEL_SHUTDOWN:
      i = runlevel_shutdown_list;
      runlevel_shutdown_list = -1;
      break;
    case RUNLEVEL_BEFORE_EXIT:
      i = runlevel_before_list;
      runlevel_before_list = -1;
      break;
    case RUNLEVEL_AFTER_EXIT:
      i = runlevel_after_list;
      runlevel_after_list = -1;
      break;
    default:
      return;
  }

  // the task_activate must differ!!! look at activate.c
  calling_runlevel_func = 1;

  while (i != -1) {
    if (!(aborting && runlevel_list[i].no_at_abort))
      runlevel_list[i].f(runlevel_list[i].arg);

    j = i;
    i = runlevel_list[i].next;

    runlevel_list[j].next = runlevel_free;
    runlevel_free = j;
  }

  calling_runlevel_func = 0;

}

/*+ Use this function to post your own runlevel operations
    (when uses some defines contained in const.h) +*/

int sys_atrunlevel(void (*func_code)(void *),void *parm, BYTE when)
{
    register int i = 0;
    SYS_FLAGS f;

    f = kern_fsave();
    if (runlevel_free == -1) {
        errno = ETOOMUCH_EXITFUNC;
        kern_frestore(f);
        return -1;
    }

    i = runlevel_free;
    runlevel_free = runlevel_list[runlevel_free].next;

    runlevel_list[i].f = func_code;
    runlevel_list[i].arg = parm;
    runlevel_list[i].no_at_abort = when & NO_AT_ABORT;

    switch (when & 0x03) {
      case RUNLEVEL_INIT:
        /* the init functions are called in the order they are posted
           so, we insert at the queue tail */

        runlevel_list[i].next = -1;
        if (runlevel_init_list == -1)
          runlevel_init_list = i;
        else
          runlevel_list[runlevel_init_tail].next = i;
        runlevel_init_tail = i;
        break;
      case RUNLEVEL_SHUTDOWN:
        runlevel_list[i].next = runlevel_shutdown_list;
        runlevel_shutdown_list = i;
        break;
      case RUNLEVEL_BEFORE_EXIT:
        runlevel_list[i].next = runlevel_before_list;
        runlevel_before_list = i;
        break;
      default: // RUNLEVEL_AFTER_EXIT
        runlevel_list[i].next = runlevel_after_list;
        runlevel_after_list = i;
    }

    kern_frestore(f);
    return 0;
}


/*+ This function returns a level_des **. the value returned shall be
    used to register a level module. The function shall be called only at
    module registration time. It assume that the system is not yet
    initialized, so we shall not call sys_abort...                     +*/

LEVEL level_alloc_descriptor()
{
  if (sched_levels == MAX_SCHED_LEVEL)
  {
    printk("Too many scheduling levels!!!\n");
    l1_exit(1);
  }

  return sched_levels++;
}


/*+ This function returns a resource_des **. the value returned shall be
    used to register a resource module. The function shall be called only at
    module registration time. It assume that the system is not yet
    initialized, so we shall not call sys_abort...                     +*/

RLEVEL resource_alloc_descriptor()
{
  if (res_levels == MAX_RES_LEVEL)
  {
    printk("Too many resource levels!!!\n");
    l1_exit(1);
  }

  return res_levels++;
}

/*+ This function compute the command line parameters from the multiboot_info
    NOTE: this function modify the multiboot struct, so this function and
    __call_main__ are mutually exclusives!!! +*/

void __compute_args__(struct multiboot_info *mbi, int *_argc, char **_argv)
{
  register int i = 0;
  char *cmdline = (char *)(mbi->cmdline);

  /* creates the command line... */
  *_argc = 0;
  if (mbi->flags & MB_INFO_CMDLINE) {
    while (cmdline[i] != 0) {
      _argv[*_argc] = &(cmdline[i]);
      while (cmdline[i] != ' ' && cmdline[i] != 0) i++;
      if (cmdline[i] == ' ') {
        cmdline[i] = 0; i++; (*_argc)++;
      }
    }
    (*_argc)++;
  }
}

/* note that the prototype is not public... so the user can
    also use a int main(void), void main(void)... and so on... */

int main(int argc, char **argv);

/*+ This function calls the standard C main() function, with a
    parameter list up to 100 parameters                        +*/

int __call_main__(struct multiboot_info *mbi)
{
  int _argc;
  char *_argv[100];
  __compute_args__(mbi, &_argc, _argv);
  return main(_argc,_argv);
}