/*
* 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;
//此函数在sys_call.s文件中
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 _syscall1(int,setup,void *,BIOS)
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 int vsprintf(char *,const char *,va_list);
extern void init(void);
extern void init_IRQ(void);
extern long kmalloc_init (long,long);
extern long blk_dev_init(long,long);
extern long chr_dev_init(long,long);
extern void floppy_init(void);
extern void sock_init(void);
extern long rd_init(long mem_start, int length);
unsigned long net_dev_init(unsigned long, unsigned long);
extern unsigned long simple_strtoul(const char *,char **,unsigned int);

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 st0x_setup(char *str, int *ints);
extern void tmc8xx_setup(char *str, int *ints);
extern void t128_setup(char *str, int *ints);
extern void generic_NCR5380_setup(char *str, int *intr);
extern void aha152x_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_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))

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[80] = { 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 },
#ifdef CONFIG_INET
{ "ether=", eth_setup },
#endif
#ifdef CONFIG_BLK_DEV_HD
{ "hd=", hd_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_GENERIC_NCR5380
{ "ncr5380=", generic_NCR5380_setup },
#endif
#ifdef CONFIG_SCSI_AHA152X
{ "aha152x=", aha152x_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
{ 0, 0 }
};

//检测设置,根据命令行中的命令,调整设置,实际上是设置各种设备的初始化函数
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(0);
}
i++;
}
return(1);
}

unsigned long loops_per_sec = 1;
//延迟校准
static void calibrate_delay(void)
{
int ticks;

printk("Calibrating delay loop.. ");
while (loops_per_sec <<= 1) {
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.
*/
//这是一个简单的内核命令行解析函数。它解析命令行参数,并且正确的填入init参数环境
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, 0xC00, 0xC40, 0};
int args, envs;

//校验参数
if (!*line)
return;
//
args = 0;
//终端默认设置为控制台模式
envs = 1; /* TERM is set to 'console' by default */
//next指向输入参数开始抵制
next = line;
//一直解析参数到结尾,分别确定根设备号、读写属性、日志级别,数学协处理器
while ((line = next) != NULL) {
//查找line字符串中的空格,将该位置置0
if ((next = strchr(line,' ')) != NULL)
*next++ = 0;
/*
* check for kernel options first..
*/
//检测内核选项

//首先检测是否有root
if (!strncmp(line,"root=",5)) {
//如果有root
int n;
line += 5;
//是否以"/dev/"开始
if (strncmp(line,"/dev/",5)) {
//如果不是,则直接将字符按16进制转换,作为根设备号
ROOT_DEV = simple_strtoul(line,NULL,16);
continue;
}
//跳过"/dev/"
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,16);
break;
}
}
} else if (!strcmp(line,"ro")) //如果不是root,则比较是否为ro,即只读
root_mountflags |= MS_RDONLY;
else if (!strcmp(line,"rw")) //是否为rw,即读写
root_mountflags &= ~MS_RDONLY;
else if (!strcmp(line,"debug")) //日志级别
console_loglevel = 10;
else if (!strcmp(line,"no387")) { //是否定义了协处理器
hard_math = 0;
__asm__("movl %%cr0,%%eax\n\t"
"orl $0xE,%%eax\n\t"
"movl %%eax,%%cr0\n\t" : : : "ax");
} else
checksetup(line); //检测设置,重新设置函数
/*
* 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;
}

//如果在命令行中定义了内存的大小的处理方法,将from内容拷贝到to中,不包含内存的大小
static void copy_options(char * to, char * from)
{
//初始化字符变量未空格
char c = ' ';

//循环处理字符串from,搜索mem=字符串,找到定义值
do {
if (c == ' ' && !memcmp("mem=", from, 4))
memory_end = simple_strtoul(from+4, &from, 0);
c = *(to++) = *(from++);
} while (c);
}

//超时处理
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);
}

//入口函数
asmlinkage void start_kernel(void)
{
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
//挂接lcall7到默认的ldt中
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;
//内存结束位置 1M位置 + 扩展内存(k)*1024
memory_end = (1<<20) + (EXT_MEM_K<<10);
//忽略不到4kb大小的内存
memory_end &= PAGE_MASK;
//ramdisk的长度
ramdisk_size = RAMDISK_SIZE;
//拷贝命令行选项,实际上就是看命令行中是否指定内存大小
// 输入参数command_line目前只有空间,COMMAND_LINE为启动参数
copy_options(command_line,COMMAND_LINE);
//内存定义超过16M的处理
#ifdef CONFIG_MAX_16M
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
#endif
//挂接只读根设备的标志
if (MOUNT_ROOT_RDONLY)
root_mountflags |= MS_RDONLY;
//如果内核所占内存超过1M
if ((unsigned long)&end >= (1024*1024)) {
//重新按照实际情况设置核心内存的开始位置
memory_start = (unsigned long) &end;
low_memory_start = PAGE_SIZE;
} else {
//否者设置主存开始处为1M内存处
memory_start = 1024*1024;
low_memory_start = (unsigned long) &end;
}
//这里如此设置,是因为没有超过的话,在1m内存之前还有剩余

//内存低地址开始处对齐
low_memory_start = PAGE_ALIGN(low_memory_start);
//初始内存页
memory_start = paging_init(memory_start,memory_end);

//判断是否为EISA总线
if (strncmp((char*)0x0FFFD9, "EISA", 4) == 0)
EISA_bus = 1;
//初始化陷阱门
trap_init();
//初始化IRQ
init_IRQ();
//任务调度初始化
sched_init();
//解析命令行
parse_options(command_line);
//配置CONFIG_PROFILE的情况下,内存布局
#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
//初始化lmalloc
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_INET
memory_start = net_dev_init(memory_start,memory_end);
#endif
//初始化scsi设备
#ifdef CONFIG_SCSI
memory_start = scsi_dev_init(memory_start,memory_end);
#endif
//初始化inode
memory_start = inode_init(memory_start,memory_end);
//初始化文件表
memory_start = file_table_init(memory_start,memory_end);
//内存初始化
mem_init(low_memory_start,memory_start,memory_end);
//高速缓冲区初始化
buffer_init();
//初始化时间
time_init();
//初始化软盘
floppy_init();
//初始化sock
sock_init();
//初始化ipc
#ifdef CONFIG_SYSVIPC
ipc_init();
#endif
sti();

/*
* 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..
*/
//数学协处理器处理
if (hard_math) {
unsigned short control_word;

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)
printk("Ok, fpu using %s error reporting.\n",
ignore_irq13?"exception 16":"irq13");
}
#ifndef CONFIG_MATH_EMULATION
else {
printk("No coprocessor found and no math emulation present.\n");
printk("Giving up.\n");
for (;;) ;
}
#endif

//
system_utsname.machine[1] = '0' + x86;
printk(linux_banner);

//转到用户空间
move_to_user_mode();
//创建新进程
if (!fork()) /* we count on this going ok */
//init进程
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;
}

//init进程
void init(void)
{
int pid,i;

setup((void *) &drive_info);
sprintf(term, "TERM=con%dx%d", ORIG_VIDEO_COLS, ORIG_VIDEO_LINES);
(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);
}

init/main.c的更多相关文章

  1. Linux0.11内核剖析--初始化程序(init)

    1.概述 在内核源代码的 init/目录中只有一个 main.c 文件. 系统在执行完 boot/目录中的 head.s 程序后就会将执行权交给 main.c.该程序虽然不长,但却包括了内核初始化的所 ...

  2. imx6 启动 init进程

    之前不知道imx6内核是怎么启动文件系统的init进程,查了下资料,记录于此,以后再来补充. kernel/init/main.c static noinline int init_post(void ...

  3. __attribute__ ((__section__ (".init.text")))

    在kernel中有很多__init,这个东东到底是何方神圣捏?且听小生我一一道来.下面是其定义:file:/include/linux/init.h 43 #define __init      __ ...

  4. Android Init进程命令的执行和服务的启动

    这里开始分析init进程中配置文件的解析,在配置文件中的命令的执行和服务的启动. 首先init是一个可执行文件,它的对应的Makfile是init/Android.mk. Android.mk定义了i ...

  5. 动静结合学内核:linux idle进程和init进程浅析

    刘柳 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 + titer1@qq.com 退休的贵族进程 ...

  6. Linux下1号进程的前世(kernel_init)今生(init进程)----Linux进程的管理与调度(六)

    前面我们了解到了0号进程是系统所有进程的先祖, 它的进程描述符init_task是内核静态创建的, 而它在进行初始化的时候, 通过kernel_thread的方式创建了两个内核线程,分别是kernel ...

  7. echarts.init 使用jq获取初始化对象

    var myChart = echarts.init($('#main')[0]);// 或者var myChart = echarts.init($('#main').get(0));

  8. 制作根文件系统之内核如何启动init进程

    start_kernel其实也是内核的一个进程,它占用了进程号0,start_kernel的内容简写如下: asmlinkage void __init start_kernel(void) //内核 ...

  9. 构建一个简单的Linux系统 MenuOs —— start_kernel到init进程(20135304刘世鹏)

    构建一个简单的Linux系统 MenuOs —— start_kernel到init进程 作者:刘世鹏20135304 <Linux内核分析>MOOC课程http://mooc.study ...

随机推荐

  1. Dictionary解析json,里面的数组放进list,并绑定到DataGridView指定列

    Dictionary解析json,1.根据json建立相应的实体类,json里面的数组形式放进list集合2.取list中的数据,将相应的数据绑定到DataGridView,如下:循环(动态添加一行数 ...

  2. java程序(一)----HashMap同时获取键值

    快速会用: HashMap<Integer,String> maps=new HashMap<Integer,String>(); maps.put(1,"xiaom ...

  3. 编译哈工大语言技术平台云LTP(C++)源码及LTP4J(Java)源码

    转自:编译哈工大语言技术平台云LTP(C++)源码及LTP4J(Java)源码 JDK:java version “1.8.0_31”Java(TM) SE Runtime Environment ( ...

  4. 【C语言学习】-01 C基础

    本文目录: 0.进制转换 1.C数据类型 2.常量变量 3.运算符 4.表达式 5.格式化输入输出 回到顶部 0.进制转换 在计算机中存储的数据,主要是以二进制形式存在,而我们生活中主要使用的有十进制 ...

  5. Rhel6-heartbeat配置文档

    系统环境: rhel6 x86_64 iptables and selinux disabled 主机: 192.168.122.119 server19.example.com 192.168.12 ...

  6. Hibernate对象映射类型

    Hibernate understands both the Java and JDBC representations of application data. The ability to rea ...

  7. Css杂谈

    CSS是Cascading Style Sheets(级联样式表)的缩写. CSS涉及字体.颜色.边距.高度.宽度.背景图像.高级定位等方面. HTML可以用于为网站添加布局效果,但有可能被误用.而C ...

  8. Android 监听ContentProvider的数据改变

    今天介绍一下怎么监听ContentProvider的数据改变,主要的方法是:getContext().getContentResolver().notifyChange(uri,null),这行代码是 ...

  9. Struts2 的ModelDriven理解

    以UserAction为例,当UserAction实现了ModelDriven接口之后,与该接口相关的默认配置的拦截器会在拦截请求之后判断该请求是将要被UserAction处理而且UserAction ...

  10. poj1458

    //Accepted 4112 KB 16 ms //最长公共子串 #include <cstdio> #include <cstring> #include <iost ...