4 * Copyright (C) 1991, 1992 Linus Torvalds
9 #include <asm/system.h>
12 #include <linux/types.h>
13 #include <linux/fcntl.h>
14 #include <linux/config.h>
15 #include <linux/sched.h>
16 #include <linux/tty.h>
17 #include <linux/head.h>
18 #include <linux/unistd.h>
19 #include <linux/string.h>
20 #include <linux/timer.h>
22 #include <linux/ctype.h>
23 #include <linux/delay.h>
24 #include <linux/utsname.h>
25 #include <linux/ioport.h>
27 extern unsigned long * prof_buffer
;
28 extern unsigned long prof_len
;
29 extern char edata
, end
;
30 extern char *linux_banner
;
31 asmlinkage
void lcall7(void);
32 struct desc_struct default_ldt
;
35 * we need this inline - forking from kernel space will result
36 * in NO COPY ON WRITE (!!!), until an execve is executed. This
37 * is no problem, but for the stack. This is handled by not letting
38 * main() use the stack at all after fork(). Thus, no function
39 * calls - which means inline code for fork too, as otherwise we
40 * would use the stack upon exit from 'fork()'.
42 * Actually only pause and fork are needed inline, so that there
43 * won't be any messing with the stack from main(), but we define
46 #define __NR__exit __NR_exit
47 static inline _syscall0(int,idle
)
48 static inline _syscall0(int,fork
)
49 static inline _syscall0(int,pause
)
50 static inline _syscall1(int,setup
,void *,BIOS
)
51 static inline _syscall0(int,sync
)
52 static inline _syscall0(pid_t
,setsid
)
53 static inline _syscall3(int,write
,int,fd
,const char *,buf
,off_t
,count
)
54 static inline _syscall1(int,dup
,int,fd
)
55 static inline _syscall3(int,execve
,const char *,file
,char **,argv
,char **,envp
)
56 static inline _syscall3(int,open
,const char *,file
,int,flag
,int,mode
)
57 static inline _syscall1(int,close
,int,fd
)
58 static inline _syscall1(int,_exit
,int,exitcode
)
59 static inline _syscall3(pid_t
,waitpid
,pid_t
,pid
,int *,wait_stat
,int,options
)
61 static inline pid_t
wait(int * wait_stat
)
63 return waitpid(-1,wait_stat
,0);
66 static char printbuf
[1024];
68 extern int console_loglevel
;
70 extern char empty_zero_page
[PAGE_SIZE
];
71 extern int vsprintf(char *,const char *,va_list);
72 extern void init(void);
73 extern void init_IRQ(void);
74 extern long kmalloc_init (long,long);
75 extern long blk_dev_init(long,long);
76 extern long chr_dev_init(long,long);
77 extern void floppy_init(void);
78 extern void sock_init(void);
79 extern long rd_init(long mem_start
, int length
);
80 unsigned long net_dev_init(unsigned long, unsigned long);
81 extern unsigned long simple_strtoul(const char *,char **,unsigned int);
83 extern void hd_setup(char *str
, int *ints
);
84 extern void bmouse_setup(char *str
, int *ints
);
85 extern void eth_setup(char *str
, int *ints
);
86 extern void xd_setup(char *str
, int *ints
);
87 extern void mcd_setup(char *str
, int *ints
);
88 extern void st0x_setup(char *str
, int *ints
);
89 extern void tmc8xx_setup(char *str
, int *ints
);
90 extern void t128_setup(char *str
, int *ints
);
91 extern void generic_NCR5380_setup(char *str
, int *intr
);
92 extern void aha152x_setup(char *str
, int *ints
);
93 extern void sound_setup(char *str
, int *ints
);
95 extern void sbpcd_setup(char *str
, int *ints
);
99 extern void ipc_init(void);
102 extern unsigned long scsi_dev_init(unsigned long, unsigned long);
106 * This is set up by the setup-routine at boot-time
108 #define PARAM empty_zero_page
109 #define EXT_MEM_K (*(unsigned short *) (PARAM+2))
110 #define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
111 #define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
112 #define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
113 #define RAMDISK_SIZE (*(unsigned short *) (PARAM+0x1F8))
114 #define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
115 #define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
118 * Boot command-line arguments
120 #define MAX_INIT_ARGS 8
121 #define MAX_INIT_ENVS 8
122 #define COMMAND_LINE ((char *) (PARAM+2048))
124 extern void time_init(void);
126 static unsigned long memory_start
= 0; /* After mem_init, stores the */
127 /* amount of free user memory */
128 static unsigned long memory_end
= 0;
129 static unsigned long low_memory_start
= 0;
131 static char term
[21];
134 static char * argv_init
[MAX_INIT_ARGS
+2] = { "init", NULL
, };
135 static char * envp_init
[MAX_INIT_ENVS
+2] = { "HOME=/", term
, NULL
, };
137 static char * argv_rc
[] = { "/bin/sh", NULL
};
138 static char * envp_rc
[] = { "HOME=/", term
, NULL
};
140 static char * argv
[] = { "-/bin/sh",NULL
};
141 static char * envp
[] = { "HOME=/usr/root", term
, NULL
};
143 struct drive_info_struct
{ char dummy
[32]; } drive_info
;
144 struct screen_info screen_info
;
146 unsigned char aux_device_present
;
148 int root_mountflags
= 0;
150 static char fpu_error
= 0;
152 static char command_line
[80] = { 0, };
154 char *get_options(char *str
, int *ints
)
159 while (cur
&& isdigit(*cur
) && i
<= 10) {
160 ints
[i
++] = simple_strtoul(cur
,NULL
,0);
161 if ((cur
= strchr(cur
,',')) != NULL
)
170 void (*setup_func
)(char *, int *);
172 { "reserve=", reserve_setup
},
174 { "ether=", eth_setup
},
176 #ifdef CONFIG_BLK_DEV_HD
179 #ifdef CONFIG_BUSMOUSE
180 { "bmouse=", bmouse_setup
},
182 #ifdef CONFIG_SCSI_SEAGATE
183 { "st0x=", st0x_setup
},
184 { "tmc8xx=", tmc8xx_setup
},
186 #ifdef CONFIG_SCSI_T128
187 { "t128=", t128_setup
},
189 #ifdef CONFIG_SCSI_GENERIC_NCR5380
190 { "ncr5380=", generic_NCR5380_setup
},
192 #ifdef CONFIG_SCSI_AHA152X
193 { "aha152x=", aha152x_setup
},
195 #ifdef CONFIG_BLK_DEV_XD
199 { "mcd=", mcd_setup
},
202 { "sound=", sound_setup
},
205 { "sbpcd=", sbpcd_setup
},
210 int checksetup(char *line
)
215 while (bootsetups
[i
].str
) {
216 int n
= strlen(bootsetups
[i
].str
);
217 if (!strncmp(line
,bootsetups
[i
].str
,n
)) {
218 bootsetups
[i
].setup_func(get_options(line
+n
,ints
), ints
);
226 unsigned long loops_per_sec
= 1;
228 static void calibrate_delay(void)
232 printk("Calibrating delay loop.. ");
233 while (loops_per_sec
<<= 1) {
235 __delay(loops_per_sec
);
236 ticks
= jiffies
- ticks
;
238 __asm__("mull %1 ; divl %2"
239 :"=a" (loops_per_sec
)
244 printk("ok - %lu.%02lu BogoMips\n",
245 loops_per_sec
/500000,
246 (loops_per_sec
/5000) % 100);
255 * This is a simple kernel command line parsing function: it parses
256 * the command line, and fills in the arguments/environment to init
257 * as appropriate. Any cmd-line option is taken to be an environment
258 * variable if it contains the character '='.
261 * This routine also checks for options meant for the kernel - currently
262 * only the "root=XXXX" option is recognized. These options are not given
263 * to init - they are for internal kernel use only.
265 static void parse_options(char *line
)
268 char *devnames
[] = { "hda", "hdb", "sda", "sdb", "sdc", "sdd", "sde", "fd", "xda", "xdb", NULL
};
269 int devnums
[] = { 0x300, 0x340, 0x800, 0x810, 0x820, 0x830, 0x840, 0x200, 0xC00, 0xC40, 0};
275 envs
= 1; /* TERM is set to 'console' by default */
277 while ((line
= next
) != NULL
) {
278 if ((next
= strchr(line
,' ')) != NULL
)
281 * check for kernel options first..
283 if (!strncmp(line
,"root=",5)) {
286 if (strncmp(line
,"/dev/",5)) {
287 ROOT_DEV
= simple_strtoul(line
,NULL
,16);
291 for (n
= 0 ; devnames
[n
] ; n
++) {
292 int len
= strlen(devnames
[n
]);
293 if (!strncmp(line
,devnames
[n
],len
)) {
294 ROOT_DEV
= devnums
[n
]+simple_strtoul(line
+len
,NULL
,16);
298 } else if (!strcmp(line
,"ro"))
299 root_mountflags
|= MS_RDONLY
;
300 else if (!strcmp(line
,"rw"))
301 root_mountflags
&= ~MS_RDONLY
;
302 else if (!strcmp(line
,"debug"))
303 console_loglevel
= 10;
304 else if (!strcmp(line
,"no387")) {
306 __asm__("movl %%cr0,%%eax\n\t"
308 "movl %%eax,%%cr0\n\t" : : : "ax");
312 * Then check if it's an environment variable or
315 if (strchr(line
,'=')) {
316 if (envs
>= MAX_INIT_ENVS
)
318 envp_init
[++envs
] = line
;
320 if (args
>= MAX_INIT_ARGS
)
322 argv_init
[++args
] = line
;
325 argv_init
[args
+1] = NULL
;
326 envp_init
[envs
+1] = NULL
;
329 static void copro_timeout(void)
332 timer_table
[COPRO_TIMER
].expires
= jiffies
+100;
333 timer_active
|= 1<<COPRO_TIMER
;
334 printk("387 failed: trying to reset\n");
335 send_sig(SIGFPE
, last_task_used_math
, 1);
340 asmlinkage
void start_kernel(void)
343 * Interrupts are still disabled. Do necessary setups, then
346 set_call_gate(&default_ldt
,lcall7
);
347 ROOT_DEV
= ORIG_ROOT_DEV
;
348 drive_info
= DRIVE_INFO
;
349 screen_info
= SCREEN_INFO
;
350 aux_device_present
= AUX_DEVICE_INFO
;
351 memory_end
= (1<<20) + (EXT_MEM_K
<<10);
352 memory_end
&= PAGE_MASK
;
353 ramdisk_size
= RAMDISK_SIZE
;
354 strcpy(command_line
,COMMAND_LINE
);
355 #ifdef CONFIG_MAX_16M
356 if (memory_end
> 16*1024*1024)
357 memory_end
= 16*1024*1024;
359 if (MOUNT_ROOT_RDONLY
)
360 root_mountflags
|= MS_RDONLY
;
361 if ((unsigned long)&end
>= (1024*1024)) {
362 memory_start
= (unsigned long) &end
;
363 low_memory_start
= PAGE_SIZE
;
365 memory_start
= 1024*1024;
366 low_memory_start
= (unsigned long) &end
;
368 low_memory_start
= PAGE_ALIGN(low_memory_start
);
369 memory_start
= paging_init(memory_start
,memory_end
);
370 if (strncmp((char*)0x0FFFD9, "EISA", 4) == 0)
375 parse_options(command_line
);
376 #ifdef CONFIG_PROFILE
377 prof_buffer
= (unsigned long *) memory_start
;
378 prof_len
= (unsigned long) &end
;
380 memory_start
+= prof_len
* sizeof(unsigned long);
382 memory_start
= kmalloc_init(memory_start
,memory_end
);
383 memory_start
= chr_dev_init(memory_start
,memory_end
);
384 memory_start
= blk_dev_init(memory_start
,memory_end
);
388 memory_start
= net_dev_init(memory_start
,memory_end
);
391 memory_start
= scsi_dev_init(memory_start
,memory_end
);
393 memory_start
= inode_init(memory_start
,memory_end
);
394 memory_start
= file_table_init(memory_start
,memory_end
);
395 mem_init(low_memory_start
,memory_start
,memory_end
);
400 #ifdef CONFIG_SYSVIPC
406 * check if exception 16 works correctly.. This is truly evil
407 * code: it disables the high 8 interrupts to make sure that
408 * the irq13 doesn't happen. But as this will lead to a lockup
409 * if no exception16 arrives, it depends on the fact that the
410 * high 8 interrupts will be re-enabled by the next timer tick.
411 * So the irq13 will happen eventually, but the exception 16
412 * should get there first..
415 unsigned short control_word
;
417 printk("Checking 386/387 coupling... ");
418 timer_table
[COPRO_TIMER
].expires
= jiffies
+50;
419 timer_table
[COPRO_TIMER
].fn
= copro_timeout
;
420 timer_active
|= 1<<COPRO_TIMER
;
421 __asm__("clts ; fninit ; fnstcw %0 ; fwait":"=m" (*&control_word
));
422 control_word
&= 0xffc0;
423 __asm__("fldcw %0 ; fwait": :"m" (*&control_word
));
424 outb_p(inb_p(0x21) | (1 << 2), 0x21);
425 __asm__("fldz ; fld1 ; fdiv %st,%st(1) ; fwait");
426 timer_active
&= ~(1<<COPRO_TIMER
);
428 printk("Ok, fpu using %s error reporting.\n",
429 ignore_irq13
?"exception 16":"irq13");
431 #ifndef CONFIG_MATH_EMULATION
433 printk("No coprocessor found and no math emulation present.\n");
434 printk("Giving up.\n");
439 system_utsname
.machine
[1] = '0' + x86
;
440 printk(linux_banner
);
443 if (!fork()) /* we count on this going ok */
446 * task[0] is meant to be used as an "idle" task: it may not sleep, but
447 * it might do some general things like count free pages or it could be
448 * used to implement a reasonable LRU algorithm for the paging routines:
449 * anything that can be useful, but shouldn't take time from the real
452 * Right now task[0] just does a infinite idle loop.
458 static int printf(const char *fmt
, ...)
464 write(1,printbuf
,i
=vsprintf(printbuf
, fmt
, args
));
473 setup((void *) &drive_info
);
474 sprintf(term
, "TERM=con%dx%d", ORIG_VIDEO_COLS
, ORIG_VIDEO_LINES
);
475 (void) open("/dev/tty1",O_RDWR
,0);
479 execve("/etc/init",argv_init
,envp_init
);
480 execve("/bin/init",argv_init
,envp_init
);
481 execve("/sbin/init",argv_init
,envp_init
);
482 /* if this fails, fall through to original stuff */
486 if (open("/etc/rc",O_RDONLY
,0))
488 execve("/bin/sh",argv_rc
,envp_rc
);
492 while (pid
!= wait(&i
))
495 if ((pid
= fork()) < 0) {
496 printf("Fork failed in init\n\r");
500 close(0);close(1);close(2);
502 (void) open("/dev/tty1",O_RDWR
,0);
505 _exit(execve("/bin/sh",argv
,envp
));
510 printf("\n\rchild %d died with code %04x\n\r",pid
,i
);