linux-old/init/main.c
<<
>>
Prefs
   1/*
   2 *  linux/init/main.c
   3 *
   4 *  Copyright (C) 1991, 1992  Linus Torvalds
   5 */
   6
   7#define __KERNEL_SYSCALLS__
   8#include <stdarg.h>
   9
  10#include <asm/system.h>
  11#include <asm/io.h>
  12
  13#include <linux/types.h>
  14#include <linux/fcntl.h>
  15#include <linux/config.h>
  16#include <linux/sched.h>
  17#include <linux/tty.h>
  18#include <linux/head.h>
  19#include <linux/unistd.h>
  20#include <linux/string.h>
  21#include <linux/timer.h>
  22#include <linux/fs.h>
  23#include <linux/ctype.h>
  24#include <linux/delay.h>
  25#include <linux/utsname.h>
  26#include <linux/ioport.h>
  27#include <linux/hdreg.h>
  28#include <linux/mm.h>
  29
  30#include <asm/bugs.h>
  31
  32extern unsigned long * prof_buffer;
  33extern unsigned long prof_len;
  34extern char etext, end;
  35extern char *linux_banner;
  36
  37static char printbuf[1024];
  38
  39extern int console_loglevel;
  40
  41extern void init(void);
  42extern void init_IRQ(void);
  43extern void init_modules(void);
  44extern long console_init(long, long);
  45extern long kmalloc_init(long,long);
  46extern long blk_dev_init(long,long);
  47extern long chr_dev_init(long,long);
  48extern void sock_init(void);
  49extern long rd_init(long mem_start, int length);
  50unsigned long net_dev_init(unsigned long, unsigned long);
  51extern long bios32_init(long, long);
  52
  53extern void bmouse_setup(char *str, int *ints);
  54extern void eth_setup(char *str, int *ints);
  55extern void xd_setup(char *str, int *ints);
  56extern void floppy_setup(char *str, int *ints);
  57extern void mcd_setup(char *str, int *ints);
  58extern void aztcd_setup(char *str, int *ints);
  59extern void st_setup(char *str, int *ints);
  60extern void st0x_setup(char *str, int *ints);
  61extern void tmc8xx_setup(char *str, int *ints);
  62extern void t128_setup(char *str, int *ints);
  63extern void pas16_setup(char *str, int *ints);
  64extern void generic_NCR5380_setup(char *str, int *intr);
  65extern void aha152x_setup(char *str, int *ints);
  66extern void aha1542_setup(char *str, int *ints);
  67extern void aha274x_setup(char *str, int *ints);
  68extern void buslogic_setup(char *str, int *ints);
  69extern void scsi_luns_setup(char *str, int *ints);
  70extern void sound_setup(char *str, int *ints);
  71#ifdef CONFIG_SBPCD
  72extern void sbpcd_setup(char *str, int *ints);
  73#endif CONFIG_SBPCD
  74#ifdef CONFIG_CDU31A
  75extern void cdu31a_setup(char *str, int *ints);
  76#endif CONFIG_CDU31A
  77#ifdef CONFIG_CDU535
  78extern void sonycd535_setup(char *str, int *ints);
  79#endif CONFIG_CDU535
  80void ramdisk_setup(char *str, int *ints);
  81
  82#ifdef CONFIG_SYSVIPC
  83extern void ipc_init(void);
  84#endif
  85#ifdef CONFIG_SCSI
  86extern unsigned long scsi_dev_init(unsigned long, unsigned long);
  87#endif
  88
  89/*
  90 * Boot command-line arguments
  91 */
  92#define MAX_INIT_ARGS 8
  93#define MAX_INIT_ENVS 8
  94
  95extern void time_init(void);
  96
  97static unsigned long memory_start = 0;
  98static unsigned long memory_end = 0;
  99
 100static char term[21];
 101int rows, cols;
 102
 103int ramdisk_size;
 104int root_mountflags = 0;
 105
 106static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
 107static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", term, NULL, };
 108
 109static char * argv_rc[] = { "/bin/sh", NULL };
 110static char * envp_rc[] = { "HOME=/", term, NULL };
 111
 112static char * argv[] = { "-/bin/sh",NULL };
 113static char * envp[] = { "HOME=/usr/root", term, NULL };
 114
 115char *get_options(char *str, int *ints)
 116{
 117        char *cur = str;
 118        int i=1;
 119
 120        while (cur && isdigit(*cur) && i <= 10) {
 121                ints[i++] = simple_strtoul(cur,NULL,0);
 122                if ((cur = strchr(cur,',')) != NULL)
 123                        cur++;
 124        }
 125        ints[0] = i-1;
 126        return(cur);
 127}
 128
 129struct {
 130        char *str;
 131        void (*setup_func)(char *, int *);
 132} bootsetups[] = {
 133        { "reserve=", reserve_setup },
 134        { "ramdisk=", ramdisk_setup },
 135#ifdef CONFIG_BUGi386
 136        { "no-hlt", no_halt },
 137        { "no387", no_387 },
 138#endif
 139#ifdef CONFIG_INET
 140        { "ether=", eth_setup },
 141#endif
 142#ifdef CONFIG_SCSI
 143        { "max_scsi_luns=", scsi_luns_setup },
 144#endif
 145#ifdef CONFIG_BLK_DEV_IDE
 146        { "hda=", hda_setup },
 147        { "hdb=", hdb_setup },
 148        { "hdc=", hdc_setup },
 149        { "hdd=", hdd_setup },
 150        { "hd=",  ide_setup },
 151#elif defined(CONFIG_BLK_DEV_HD)
 152        { "hd=", hd_setup },
 153#endif
 154#ifdef CONFIG_CHR_DEV_ST
 155        { "st=", st_setup },
 156#endif
 157#ifdef CONFIG_BUSMOUSE
 158        { "bmouse=", bmouse_setup },
 159#endif
 160#ifdef CONFIG_SCSI_SEAGATE
 161        { "st0x=", st0x_setup },
 162        { "tmc8xx=", tmc8xx_setup },
 163#endif
 164#ifdef CONFIG_SCSI_T128
 165        { "t128=", t128_setup },
 166#endif
 167#ifdef CONFIG_SCSI_PAS16
 168        { "pas16=", pas16_setup },
 169#endif
 170#ifdef CONFIG_SCSI_GENERIC_NCR5380
 171        { "ncr5380=", generic_NCR5380_setup },
 172#endif
 173#ifdef CONFIG_SCSI_AHA152X
 174        { "aha152x=", aha152x_setup},
 175#endif
 176#ifdef CONFIG_SCSI_AHA1542
 177        { "aha1542=", aha1542_setup},
 178#endif
 179#ifdef CONFIG_SCSI_AHA274X
 180        { "aha274x=", aha274x_setup},
 181#endif
 182#ifdef CONFIG_SCSI_BUSLOGIC
 183        { "buslogic=", buslogic_setup},
 184#endif
 185#ifdef CONFIG_BLK_DEV_XD
 186        { "xd=", xd_setup },
 187#endif
 188#ifdef CONFIG_BLK_DEV_FD
 189        { "floppy=", floppy_setup },
 190#endif
 191#ifdef CONFIG_MCD
 192        { "mcd=", mcd_setup },
 193#endif
 194#ifdef CONFIG_AZTCD
 195        { "aztcd=", aztcd_setup },
 196#endif
 197#ifdef CONFIG_CDU535
 198        { "sonycd535=", sonycd535_setup },
 199#endif CONFIG_CDU535
 200#ifdef CONFIG_SOUND
 201        { "sound=", sound_setup },
 202#endif
 203#ifdef CONFIG_SBPCD
 204        { "sbpcd=", sbpcd_setup },
 205#endif CONFIG_SBPCD
 206#ifdef CONFIG_CDU31A
 207        { "cdu31a=", cdu31a_setup },
 208#endif CONFIG_CDU31A
 209        { 0, 0 }
 210};
 211
 212void ramdisk_setup(char *str, int *ints)
 213{
 214   if (ints[0] > 0 && ints[1] >= 0)
 215      ramdisk_size = ints[1];
 216}
 217
 218static int checksetup(char *line)
 219{
 220        int i = 0;
 221        int ints[11];
 222
 223        while (bootsetups[i].str) {
 224                int n = strlen(bootsetups[i].str);
 225                if (!strncmp(line,bootsetups[i].str,n)) {
 226                        bootsetups[i].setup_func(get_options(line+n,ints), ints);
 227                        return 1;
 228                }
 229                i++;
 230        }
 231        return 0;
 232}
 233
 234unsigned long loops_per_sec = 1;
 235
 236static void calibrate_delay(void)
 237{
 238        int ticks;
 239
 240        printk("Calibrating delay loop.. ");
 241        while (loops_per_sec <<= 1) {
 242                /* wait for "start of" clock tick */
 243                ticks = jiffies;
 244                while (ticks == jiffies)
 245                        /* nothing */;
 246                /* Go .. */
 247                ticks = jiffies;
 248                __delay(loops_per_sec);
 249                ticks = jiffies - ticks;
 250                if (ticks >= HZ) {
 251                        loops_per_sec = muldiv(loops_per_sec, HZ, ticks);
 252                        printk("ok - %lu.%02lu BogoMips\n",
 253                                loops_per_sec/500000,
 254                                (loops_per_sec/5000) % 100);
 255                        return;
 256                }
 257        }
 258        printk("failed\n");
 259}
 260
 261
 262/*
 263 * This is a simple kernel command line parsing function: it parses
 264 * the command line, and fills in the arguments/environment to init
 265 * as appropriate. Any cmd-line option is taken to be an environment
 266 * variable if it contains the character '='.
 267 *
 268 *
 269 * This routine also checks for options meant for the kernel.
 270 * These options are not given to init - they are for internal kernel use only.
 271 */
 272static void parse_options(char *line)
 273{
 274        char *next;
 275        char *devnames[] = { "hda", "hdb", "hdc", "hdd", "sda", "sdb", "sdc", "sdd", "sde", "fd", "xda", "xdb", NULL };
 276        int devnums[]    = { 0x300, 0x340, 0x1600, 0x1640, 0x800, 0x810, 0x820, 0x830, 0x840, 0x200, 0xD00, 0xD40, 0};
 277        int args, envs;
 278
 279        if (!*line)
 280                return;
 281        args = 0;
 282        envs = 1;       /* TERM is set to 'console' by default */
 283        next = line;
 284        while ((line = next) != NULL) {
 285                if ((next = strchr(line,' ')) != NULL)
 286                        *next++ = 0;
 287                /*
 288                 * check for kernel options first..
 289                 */
 290                if (!strncmp(line,"root=",5)) {
 291                        int n;
 292                        line += 5;
 293                        if (strncmp(line,"/dev/",5)) {
 294                                ROOT_DEV = simple_strtoul(line,NULL,16);
 295                                continue;
 296                        }
 297                        line += 5;
 298                        for (n = 0 ; devnames[n] ; n++) {
 299                                int len = strlen(devnames[n]);
 300                                if (!strncmp(line,devnames[n],len)) {
 301                                        ROOT_DEV = devnums[n]+simple_strtoul(line+len,NULL,0);
 302                                        break;
 303                                }
 304                        }
 305                        continue;
 306                }
 307                if (!strcmp(line,"ro")) {
 308                        root_mountflags |= MS_RDONLY;
 309                        continue;
 310                }
 311                if (!strcmp(line,"rw")) {
 312                        root_mountflags &= ~MS_RDONLY;
 313                        continue;
 314                }
 315                if (!strcmp(line,"debug")) {
 316                        console_loglevel = 10;
 317                        continue;
 318                }
 319                if (checksetup(line))
 320                        continue;
 321                /*
 322                 * Then check if it's an environment variable or
 323                 * an option.
 324                 */
 325                if (strchr(line,'=')) {
 326                        if (envs >= MAX_INIT_ENVS)
 327                                break;
 328                        envp_init[++envs] = line;
 329                } else {
 330                        if (args >= MAX_INIT_ARGS)
 331                                break;
 332                        argv_init[++args] = line;
 333                }
 334        }
 335        argv_init[args+1] = NULL;
 336        envp_init[envs+1] = NULL;
 337}
 338
 339extern void check_bugs(void);
 340extern void setup_arch(char **, unsigned long *, unsigned long *);
 341
 342asmlinkage void start_kernel(void)
 343{
 344        char * command_line;
 345/*
 346 * Interrupts are still disabled. Do necessary setups, then
 347 * enable them
 348 */
 349        setup_arch(&command_line, &memory_start, &memory_end);
 350        memory_start = paging_init(memory_start,memory_end);
 351        trap_init();
 352        init_IRQ();
 353        sched_init();
 354        parse_options(command_line);
 355        init_modules();
 356#ifdef CONFIG_PROFILE
 357        prof_buffer = (unsigned long *) memory_start;
 358        /* only text is profiled */
 359        prof_len = (unsigned long) &etext;
 360        prof_len >>= CONFIG_PROFILE_SHIFT;
 361        memory_start += prof_len * sizeof(unsigned long);
 362#endif
 363        memory_start = console_init(memory_start,memory_end);
 364        memory_start = bios32_init(memory_start,memory_end);
 365        memory_start = kmalloc_init(memory_start,memory_end);
 366        sti();
 367        calibrate_delay();
 368        memory_start = chr_dev_init(memory_start,memory_end);
 369        memory_start = blk_dev_init(memory_start,memory_end);
 370        sti();
 371#ifdef CONFIG_SCSI
 372        memory_start = scsi_dev_init(memory_start,memory_end);
 373#endif
 374#ifdef CONFIG_INET
 375        memory_start = net_dev_init(memory_start,memory_end);
 376#endif
 377        memory_start = inode_init(memory_start,memory_end);
 378        memory_start = file_table_init(memory_start,memory_end);
 379        memory_start = name_cache_init(memory_start,memory_end);
 380        mem_init(memory_start,memory_end);
 381        buffer_init();
 382        time_init();
 383        sock_init();
 384#ifdef CONFIG_SYSVIPC
 385        ipc_init();
 386#endif
 387        sti();
 388        check_bugs();
 389
 390        printk(linux_banner);
 391
 392        if (!fork())            /* we count on this going ok */
 393                init();
 394/*
 395 * task[0] is meant to be used as an "idle" task: it may not sleep, but
 396 * it might do some general things like count free pages or it could be
 397 * used to implement a reasonable LRU algorithm for the paging routines:
 398 * anything that can be useful, but shouldn't take time from the real
 399 * processes.
 400 *
 401 * Right now task[0] just does a infinite idle loop.
 402 */
 403        for(;;)
 404                idle();
 405}
 406
 407static int printf(const char *fmt, ...)
 408{
 409        va_list args;
 410        int i;
 411
 412        va_start(args, fmt);
 413        write(1,printbuf,i=vsprintf(printbuf, fmt, args));
 414        va_end(args);
 415        return i;
 416}
 417
 418void init(void)
 419{
 420        int pid,i;
 421
 422        setup();
 423        sprintf(term, "TERM=con%dx%d", ORIG_VIDEO_COLS, ORIG_VIDEO_LINES);
 424
 425        #ifdef CONFIG_UMSDOS_FS
 426        {
 427                /*
 428                        When mounting a umsdos fs as root, we detect
 429                        the pseudo_root (/linux) and initialise it here.
 430                        pseudo_root is defined in fs/umsdos/inode.c
 431                */
 432                extern struct inode *pseudo_root;
 433                if (pseudo_root != NULL){
 434                        current->fs->root = pseudo_root;
 435                        current->fs->pwd  = pseudo_root;
 436                }
 437        }
 438        #endif
 439
 440        (void) open("/dev/tty1",O_RDWR,0);
 441        (void) dup(0);
 442        (void) dup(0);
 443
 444        execve("/etc/init",argv_init,envp_init);
 445        execve("/bin/init",argv_init,envp_init);
 446        execve("/sbin/init",argv_init,envp_init);
 447        /* if this fails, fall through to original stuff */
 448
 449        if (!(pid=fork())) {
 450                close(0);
 451                if (open("/etc/rc",O_RDONLY,0))
 452                        _exit(1);
 453                execve("/bin/sh",argv_rc,envp_rc);
 454                _exit(2);
 455        }
 456        if (pid>0)
 457                while (pid != wait(&i))
 458                        /* nothing */;
 459        while (1) {
 460                if ((pid = fork()) < 0) {
 461                        printf("Fork failed in init\n\r");
 462                        continue;
 463                }
 464                if (!pid) {
 465                        close(0);close(1);close(2);
 466                        setsid();
 467                        (void) open("/dev/tty1",O_RDWR,0);
 468                        (void) dup(0);
 469                        (void) dup(0);
 470                        _exit(execve("/bin/sh",argv,envp));
 471                }
 472                while (1)
 473                        if (pid == wait(&i))
 474                                break;
 475                printf("\n\rchild %d died with code %04x\n\r",pid,i);
 476                sync();
 477        }
 478        _exit(0);
 479}
 480
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.