diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1994-12-01 08:00:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1994-12-01 08:00:00 +0000 |
commit | 90ecc248e200fee448001248dde0ca540dd3ef64 (patch) | |
tree | a3fe89494ce63b4835f0f9cf5c45e74cde88252b /init/main.c | |
parent | 1513ff9b7899ab588401c89db0e99903dbf5f886 (diff) |
Import of Linux/MIPS 1.1.68
Diffstat (limited to 'init/main.c')
-rw-r--r-- | init/main.c | 648 |
1 files changed, 0 insertions, 648 deletions
diff --git a/init/main.c b/init/main.c deleted file mode 100644 index ceaabb60f..000000000 --- a/init/main.c +++ /dev/null @@ -1,648 +0,0 @@ -/* - * linux/init/main.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#include <stdarg.h> - -#include <asm/system.h> -#include <asm/io.h> - -#include <linux/types.h> -#include <linux/fcntl.h> -#include <linux/config.h> -#include <linux/sched.h> -#include <linux/tty.h> -#include <linux/head.h> -#include <linux/unistd.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/fs.h> -#include <linux/ctype.h> -#include <linux/delay.h> -#include <linux/utsname.h> -#include <linux/ioport.h> - -extern unsigned long * prof_buffer; -extern unsigned long prof_len; -extern char edata, end; -extern char *linux_banner; -asmlinkage void lcall7(void); -struct desc_struct default_ldt; - -/* - * we need this inline - forking from kernel space will result - * in NO COPY ON WRITE (!!!), until an execve is executed. This - * is no problem, but for the stack. This is handled by not letting - * main() use the stack at all after fork(). Thus, no function - * calls - which means inline code for fork too, as otherwise we - * would use the stack upon exit from 'fork()'. - * - * Actually only pause and fork are needed inline, so that there - * won't be any messing with the stack from main(), but we define - * some others too. - */ -#define __NR__exit __NR_exit -static inline _syscall0(int,idle) -static inline _syscall0(int,fork) -static inline _syscall0(int,pause) -static inline _syscall0(int,setup) -static inline _syscall0(int,sync) -static inline _syscall0(pid_t,setsid) -static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) -static inline _syscall1(int,dup,int,fd) -static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) -static inline _syscall3(int,open,const char *,file,int,flag,int,mode) -static inline _syscall1(int,close,int,fd) -static inline _syscall1(int,_exit,int,exitcode) -static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) - -static inline pid_t wait(int * wait_stat) -{ - return waitpid(-1,wait_stat,0); -} - -static char printbuf[1024]; - -extern int console_loglevel; - -extern char empty_zero_page[PAGE_SIZE]; -extern void init(void); -extern void init_IRQ(void); -extern void init_modules(void); -extern long console_init(long, long); -extern long kmalloc_init(long,long); -extern long blk_dev_init(long,long); -extern long chr_dev_init(long,long); -extern void sock_init(void); -extern long rd_init(long mem_start, int length); -unsigned long net_dev_init(unsigned long, unsigned long); -extern long bios32_init(long, long); - -extern void hd_setup(char *str, int *ints); -extern void bmouse_setup(char *str, int *ints); -extern void eth_setup(char *str, int *ints); -extern void xd_setup(char *str, int *ints); -extern void mcd_setup(char *str, int *ints); -extern void st_setup(char *str, int *ints); -extern void st0x_setup(char *str, int *ints); -extern void tmc8xx_setup(char *str, int *ints); -extern void t128_setup(char *str, int *ints); -extern void pas16_setup(char *str, int *ints); -extern void generic_NCR5380_setup(char *str, int *intr); -extern void aha152x_setup(char *str, int *ints); -extern void aha1542_setup(char *str, int *ints); -extern void aha274x_setup(char *str, int *ints); -extern void scsi_luns_setup(char *str, int *ints); -extern void sound_setup(char *str, int *ints); -#ifdef CONFIG_SBPCD -extern void sbpcd_setup(char *str, int *ints); -#endif CONFIG_SBPCD -#ifdef CONFIG_CDU31A -extern void cdu31a_setup(char *str, int *ints); -#endif CONFIG_CDU31A -void ramdisk_setup(char *str, int *ints); - -#ifdef CONFIG_SYSVIPC -extern void ipc_init(void); -#endif -#ifdef CONFIG_SCSI -extern unsigned long scsi_dev_init(unsigned long, unsigned long); -#endif - -/* - * This is set up by the setup-routine at boot-time - */ -#define PARAM empty_zero_page -#define EXT_MEM_K (*(unsigned short *) (PARAM+2)) -#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80)) -#define SCREEN_INFO (*(struct screen_info *) (PARAM+0)) -#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2)) -#define RAMDISK_SIZE (*(unsigned short *) (PARAM+0x1F8)) -#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC)) -#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF)) - -/* - * Boot command-line arguments - */ -#define MAX_INIT_ARGS 8 -#define MAX_INIT_ENVS 8 -#define COMMAND_LINE ((char *) (PARAM+2048)) -#define COMMAND_LINE_SIZE 256 - -extern void time_init(void); - -static unsigned long memory_start = 0; /* After mem_init, stores the */ - /* amount of free user memory */ -static unsigned long memory_end = 0; -static unsigned long low_memory_start = 0; - -static char term[21]; -int rows, cols; - -static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; -static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", term, NULL, }; - -static char * argv_rc[] = { "/bin/sh", NULL }; -static char * envp_rc[] = { "HOME=/", term, NULL }; - -static char * argv[] = { "-/bin/sh",NULL }; -static char * envp[] = { "HOME=/usr/root", term, NULL }; - -struct drive_info_struct { char dummy[32]; } drive_info; -struct screen_info screen_info; - -unsigned char aux_device_present; -int ramdisk_size; -int root_mountflags = 0; - -static char fpu_error = 0; - -static char command_line[COMMAND_LINE_SIZE] = { 0, }; - -char *get_options(char *str, int *ints) -{ - char *cur = str; - int i=1; - - while (cur && isdigit(*cur) && i <= 10) { - ints[i++] = simple_strtoul(cur,NULL,0); - if ((cur = strchr(cur,',')) != NULL) - cur++; - } - ints[0] = i-1; - return(cur); -} - -struct { - char *str; - void (*setup_func)(char *, int *); -} bootsetups[] = { - { "reserve=", reserve_setup }, - { "ramdisk=", ramdisk_setup }, -#ifdef CONFIG_INET - { "ether=", eth_setup }, -#endif -#ifdef CONFIG_SCSI - { "max_scsi_luns=", scsi_luns_setup }, -#endif -#ifdef CONFIG_BLK_DEV_HD - { "hd=", hd_setup }, -#endif -#ifdef CONFIG_CHR_DEV_ST - { "st=", st_setup }, -#endif -#ifdef CONFIG_BUSMOUSE - { "bmouse=", bmouse_setup }, -#endif -#ifdef CONFIG_SCSI_SEAGATE - { "st0x=", st0x_setup }, - { "tmc8xx=", tmc8xx_setup }, -#endif -#ifdef CONFIG_SCSI_T128 - { "t128=", t128_setup }, -#endif -#ifdef CONFIG_SCSI_PAS16 - { "pas16=", pas16_setup }, -#endif -#ifdef CONFIG_SCSI_GENERIC_NCR5380 - { "ncr5380=", generic_NCR5380_setup }, -#endif -#ifdef CONFIG_SCSI_AHA152X - { "aha152x=", aha152x_setup}, -#endif -#ifdef CONFIG_SCSI_AHA1542 - { "aha1542=", aha1542_setup}, -#endif -#ifdef CONFIG_SCSI_AHA274X - { "aha274x=", aha274x_setup}, -#endif -#ifdef CONFIG_BLK_DEV_XD - { "xd=", xd_setup }, -#endif -#ifdef CONFIG_MCD - { "mcd=", mcd_setup }, -#endif -#ifdef CONFIG_SOUND - { "sound=", sound_setup }, -#endif -#ifdef CONFIG_SBPCD - { "sbpcd=", sbpcd_setup }, -#endif CONFIG_SBPCD -#ifdef CONFIG_CDU31A - { "cdu31a=", cdu31a_setup }, -#endif CONFIG_CDU31A - { 0, 0 } -}; - -void ramdisk_setup(char *str, int *ints) -{ - if (ints[0] > 0 && ints[1] >= 0) - ramdisk_size = ints[1]; -} - -static int checksetup(char *line) -{ - int i = 0; - int ints[11]; - - while (bootsetups[i].str) { - int n = strlen(bootsetups[i].str); - if (!strncmp(line,bootsetups[i].str,n)) { - bootsetups[i].setup_func(get_options(line+n,ints), ints); - return 1; - } - i++; - } - return 0; -} - -unsigned long loops_per_sec = 1; - -static void calibrate_delay(void) -{ - int ticks; - - printk("Calibrating delay loop.. "); - while (loops_per_sec <<= 1) { - /* wait for "start of" clock tick */ - ticks = jiffies; - while (ticks == jiffies) - /* nothing */; - /* Go .. */ - ticks = jiffies; - __delay(loops_per_sec); - ticks = jiffies - ticks; - if (ticks >= HZ) { - __asm__("mull %1 ; divl %2" - :"=a" (loops_per_sec) - :"d" (HZ), - "r" (ticks), - "0" (loops_per_sec) - :"dx"); - printk("ok - %lu.%02lu BogoMips\n", - loops_per_sec/500000, - (loops_per_sec/5000) % 100); - return; - } - } - printk("failed\n"); -} - - -/* - * This is a simple kernel command line parsing function: it parses - * the command line, and fills in the arguments/environment to init - * as appropriate. Any cmd-line option is taken to be an environment - * variable if it contains the character '='. - * - * - * This routine also checks for options meant for the kernel - currently - * only the "root=XXXX" option is recognized. These options are not given - * to init - they are for internal kernel use only. - */ -static void parse_options(char *line) -{ - char *next; - char *devnames[] = { "hda", "hdb", "sda", "sdb", "sdc", "sdd", "sde", "fd", "xda", "xdb", NULL }; - int devnums[] = { 0x300, 0x340, 0x800, 0x810, 0x820, 0x830, 0x840, 0x200, 0xD00, 0xD40, 0}; - int args, envs; - - if (!*line) - return; - args = 0; - envs = 1; /* TERM is set to 'console' by default */ - next = line; - while ((line = next) != NULL) { - if ((next = strchr(line,' ')) != NULL) - *next++ = 0; - /* - * check for kernel options first.. - */ - if (!strncmp(line,"root=",5)) { - int n; - line += 5; - if (strncmp(line,"/dev/",5)) { - ROOT_DEV = simple_strtoul(line,NULL,16); - continue; - } - line += 5; - for (n = 0 ; devnames[n] ; n++) { - int len = strlen(devnames[n]); - if (!strncmp(line,devnames[n],len)) { - ROOT_DEV = devnums[n]+simple_strtoul(line+len,NULL,0); - break; - } - } - continue; - } - if (!strcmp(line,"ro")) { - root_mountflags |= MS_RDONLY; - continue; - } - if (!strcmp(line,"rw")) { - root_mountflags &= ~MS_RDONLY; - continue; - } - if (!strcmp(line,"debug")) { - console_loglevel = 10; - continue; - } - if (!strcmp(line,"no-hlt")) { - hlt_works_ok = 0; - continue; - } - if (!strcmp(line,"no387")) { - hard_math = 0; - __asm__("movl %%cr0,%%eax\n\t" - "orl $0xE,%%eax\n\t" - "movl %%eax,%%cr0\n\t" : : : "ax"); - continue; - } - if (checksetup(line)) - continue; - /* - * Then check if it's an environment variable or - * an option. - */ - if (strchr(line,'=')) { - if (envs >= MAX_INIT_ENVS) - break; - envp_init[++envs] = line; - } else { - if (args >= MAX_INIT_ARGS) - break; - argv_init[++args] = line; - } - } - argv_init[args+1] = NULL; - envp_init[envs+1] = NULL; -} - -static void copy_options(char * to, char * from) -{ - char c = ' '; - int len = 0; - - for (;;) { - if (c == ' ' && *(unsigned long *)from == *(unsigned long *)"mem=") - memory_end = simple_strtoul(from+4, &from, 0); - c = *(from++); - if (!c) - break; - if (COMMAND_LINE_SIZE <= ++len) - break; - *(to++) = c; - } - *to = '\0'; -} - -static void copro_timeout(void) -{ - fpu_error = 1; - timer_table[COPRO_TIMER].expires = jiffies+100; - timer_active |= 1<<COPRO_TIMER; - printk("387 failed: trying to reset\n"); - send_sig(SIGFPE, last_task_used_math, 1); - outb_p(0,0xf1); - outb_p(0,0xf0); -} - -static void check_fpu(void) -{ - static double x = 4195835.0; - static double y = 3145727.0; - unsigned short control_word; - int i; - - if (!hard_math) { -#ifndef CONFIG_MATH_EMULATION - printk("No coprocessor found and no math emulation present.\n"); - printk("Giving up.\n"); - for (;;) ; -#endif - return; - } - /* - * check if exception 16 works correctly.. This is truly evil - * code: it disables the high 8 interrupts to make sure that - * the irq13 doesn't happen. But as this will lead to a lockup - * if no exception16 arrives, it depends on the fact that the - * high 8 interrupts will be re-enabled by the next timer tick. - * So the irq13 will happen eventually, but the exception 16 - * should get there first.. - */ - printk("Checking 386/387 coupling... "); - timer_table[COPRO_TIMER].expires = jiffies+50; - timer_table[COPRO_TIMER].fn = copro_timeout; - timer_active |= 1<<COPRO_TIMER; - __asm__("clts ; fninit ; fnstcw %0 ; fwait":"=m" (*&control_word)); - control_word &= 0xffc0; - __asm__("fldcw %0 ; fwait": :"m" (*&control_word)); - outb_p(inb_p(0x21) | (1 << 2), 0x21); - __asm__("fldz ; fld1 ; fdiv %st,%st(1) ; fwait"); - timer_active &= ~(1<<COPRO_TIMER); - if (fpu_error) - return; - if (!ignore_irq13) { - printk("Ok, fpu using old IRQ13 error reporting\n"); - return; - } - __asm__("fninit\n\t" - "fldl %1\n\t" - "fdivl %2\n\t" - "fmull %2\n\t" - "fldl %1\n\t" - "fsubp %%st,%%st(1)\n\t" - "fistpl %0\n\t" - "fwait\n\t" - "fninit" - : "=m" (*&i) - : "m" (*&x), "m" (*&y)); - if (!i) { - printk("Ok, fpu using exception 16 error reporting.\n"); - return; - - } - printk("Ok, FDIV bug i%c86 system\n", '0'+x86); -} - -static void check_hlt(void) -{ - printk("Checking 'hlt' instruction... "); - if (!hlt_works_ok) { - printk("disabled\n"); - return; - } - __asm__ __volatile__("hlt ; hlt ; hlt ; hlt"); - printk("Ok.\n"); -} - -static void check_bugs(void) -{ - check_fpu(); - check_hlt(); -} - -asmlinkage void start_kernel(void) -{ -/* - * Interrupts are still disabled. Do necessary setups, then - * enable them - */ - set_call_gate(&default_ldt,lcall7); - ROOT_DEV = ORIG_ROOT_DEV; - drive_info = DRIVE_INFO; - screen_info = SCREEN_INFO; - aux_device_present = AUX_DEVICE_INFO; - memory_end = (1<<20) + (EXT_MEM_K<<10); - memory_end &= PAGE_MASK; - ramdisk_size = RAMDISK_SIZE; - copy_options(command_line,COMMAND_LINE); -#ifdef CONFIG_MAX_16M - if (memory_end > 16*1024*1024) - memory_end = 16*1024*1024; -#endif - if (MOUNT_ROOT_RDONLY) - root_mountflags |= MS_RDONLY; - if ((unsigned long)&end >= (1024*1024)) { - memory_start = (unsigned long) &end; - low_memory_start = PAGE_SIZE; - } else { - memory_start = 1024*1024; - low_memory_start = (unsigned long) &end; - } - low_memory_start = PAGE_ALIGN(low_memory_start); - memory_start = paging_init(memory_start,memory_end); - if (strncmp((char*)0x0FFFD9, "EISA", 4) == 0) - EISA_bus = 1; - trap_init(); - init_IRQ(); - sched_init(); - parse_options(command_line); - init_modules(); -#ifdef CONFIG_PROFILE - prof_buffer = (unsigned long *) memory_start; - prof_len = (unsigned long) &end; - prof_len >>= 2; - memory_start += prof_len * sizeof(unsigned long); -#endif - memory_start = console_init(memory_start,memory_end); - memory_start = bios32_init(memory_start,memory_end); - memory_start = kmalloc_init(memory_start,memory_end); - memory_start = chr_dev_init(memory_start,memory_end); - memory_start = blk_dev_init(memory_start,memory_end); - sti(); - calibrate_delay(); -#ifdef CONFIG_SCSI - memory_start = scsi_dev_init(memory_start,memory_end); -#endif -#ifdef CONFIG_INET - memory_start = net_dev_init(memory_start,memory_end); -#endif - memory_start = inode_init(memory_start,memory_end); - memory_start = file_table_init(memory_start,memory_end); - memory_start = name_cache_init(memory_start,memory_end); - mem_init(low_memory_start,memory_start,memory_end); - buffer_init(); - time_init(); - sock_init(); -#ifdef CONFIG_SYSVIPC - ipc_init(); -#endif - sti(); - check_bugs(); - - system_utsname.machine[1] = '0' + x86; - printk(linux_banner); - - move_to_user_mode(); - if (!fork()) /* we count on this going ok */ - init(); -/* - * task[0] is meant to be used as an "idle" task: it may not sleep, but - * it might do some general things like count free pages or it could be - * used to implement a reasonable LRU algorithm for the paging routines: - * anything that can be useful, but shouldn't take time from the real - * processes. - * - * Right now task[0] just does a infinite idle loop. - */ - for(;;) - idle(); -} - -static int printf(const char *fmt, ...) -{ - va_list args; - int i; - - va_start(args, fmt); - write(1,printbuf,i=vsprintf(printbuf, fmt, args)); - va_end(args); - return i; -} - -void init(void) -{ - int pid,i; - - setup(); - sprintf(term, "TERM=con%dx%d", ORIG_VIDEO_COLS, ORIG_VIDEO_LINES); - - #ifdef CONFIG_UMSDOS_FS - { - /* - When mounting a umsdos fs as root, we detect - the pseudo_root (/linux) and initialise it here. - pseudo_root is defined in fs/umsdos/inode.c - */ - extern struct inode *pseudo_root; - if (pseudo_root != NULL){ - current->fs->root = pseudo_root; - current->fs->pwd = pseudo_root; - } - } - #endif - - (void) open("/dev/tty1",O_RDWR,0); - (void) dup(0); - (void) dup(0); - - execve("/etc/init",argv_init,envp_init); - execve("/bin/init",argv_init,envp_init); - execve("/sbin/init",argv_init,envp_init); - /* if this fails, fall through to original stuff */ - - if (!(pid=fork())) { - close(0); - if (open("/etc/rc",O_RDONLY,0)) - _exit(1); - execve("/bin/sh",argv_rc,envp_rc); - _exit(2); - } - if (pid>0) - while (pid != wait(&i)) - /* nothing */; - while (1) { - if ((pid = fork()) < 0) { - printf("Fork failed in init\n\r"); - continue; - } - if (!pid) { - close(0);close(1);close(2); - setsid(); - (void) open("/dev/tty1",O_RDWR,0); - (void) dup(0); - (void) dup(0); - _exit(execve("/bin/sh",argv,envp)); - } - while (1) - if (pid == wait(&i)) - break; - printf("\n\rchild %d died with code %04x\n\r",pid,i); - sync(); - } - _exit(0); -} |