linux系统启动main.c分析

为了使用unistd.h中的宏,该宏用来进行系统调用,
系统调用是通过0x80进行的,防止使用用户栈空间。
#define __LIBRARY__
#include <unistd.h>
#include <time.h>

声明系统调用,采用内联的方式。
fork系统调用
static inline _syscall0(int,fork)
pause系统调用
static inline _syscall0(int,pause)
setup系统调用
static inline _syscall1(int,setup,void *,BIOS)
sync系统调用
static inline _syscall0(int,sync)

#include <linux/tty.h>
#include <linux/sched.h>
#include <linux/head.h>
#include <asm/system.h>
#include <asm/io.h>

#include <stddef.h>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>

#include <linux/fs.h>

static char printbuf[1024];

extern int vsprintf();
extern void init(void);
extern void blk_dev_init(void);
extern void chr_dev_init(void);
extern void hd_init(void);
extern void floppy_init(void);
extern void mem_init(long start, long end);
extern long rd_init(long mem_start, int length);
extern long kernel_mktime(struct tm * tm);
extern long startup_time;

参见setup.s中,通过BIOS中断加载的系统参数。
扩展内存大小
#define EXT_MEM_K (*(unsigned short *)0x90002)
硬盘参数表
#define DRIVE_INFO (*(struct drive_info *)0x90080)
根文件系统的设备号
#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)

读取CMOS的实时钟
#define CMOS_READ(addr) ({ /
outb_p(0x80|addr,0x70); /
inb_p(0x71); /
})

将BCD码转换成二进制码
#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)

将实时钟时间转换成1970年1月1日0时开始的秒数
static void time_init(void)
{
 struct tm time;

 do {
  time.tm_sec = CMOS_READ(0);
  time.tm_min = CMOS_READ(2);
  time.tm_hour = CMOS_READ(4);
  time.tm_mday = CMOS_READ(7);
  time.tm_mon = CMOS_READ(8);
  time.tm_year = CMOS_READ(9);
 } while (time.tm_sec != CMOS_READ(0));
 BCD_TO_BIN(time.tm_sec);
 BCD_TO_BIN(time.tm_min);
 BCD_TO_BIN(time.tm_hour);
 BCD_TO_BIN(time.tm_mday);
 BCD_TO_BIN(time.tm_mon);
 BCD_TO_BIN(time.tm_year);
 time.tm_mon--;
 startup_time = kernel_mktime(&time);
}

static long memory_end = 0;
static long buffer_memory_end = 0;
static long main_memory_start = 0;

struct drive_info { char dummy[32]; } drive_info;

main函数的返回类型是void,由head.s压入栈时决定的。
void main(void)  

 对根文件系统设备号进行付值  
  ROOT_DEV = ORIG_ROOT_DEV;
 对硬盘参数表进行付值
  drive_info = DRIVE_INFO;
 计算内存结束位置,1M+扩展内存
 memory_end = (1<<20) + (EXT_MEM_K<<10);
 内存结束地址4k对齐
 memory_end &= 0xfffff000;
 if (memory_end > 16*1024*1024)
  memory_end = 16*1024*1024;
 if (memory_end > 12*1024*1024)
  buffer_memory_end = 4*1024*1024;
 else if (memory_end > 6*1024*1024)
  buffer_memory_end = 2*1024*1024;
 else
  buffer_memory_end = 1*1024*1024;
 main_memory_start = buffer_memory_end;
如果编译内核的时候选择了虚拟盘参数,则内存的开始位置需要考虑虚拟盘所占空间
#ifdef RAMDISK
 main_memory_start += rd_init(main_memory_start, RAMDISK*1024);
#endif
 进行一系列的初始化操作
 内存初始化
 mem_init(main_memory_start,memory_end);
 陷阱门初始化
 trap_init();
 块设备初始化
 blk_dev_init();
 字符设备初始化
 chr_dev_init();
 终端程序初始化
 tty_init();
 时间程序初始化,开机时间
 time_init();
 调度程序初始化
 sched_init();
 高速缓存初始化
 buffer_init(buffer_memory_end);
 硬盘初始化
 hd_init();
 软盘驱动程序的初始化
 floppy_init();

 允许中断
 sti();
 move_to_user_mode();
 创建子进程
 if (!fork()) {
  在进程1中执行init程序 
  init();
 }

 等待init进程退出
 for(;;) pause();
}

定义printf函数。
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;
}

static char * argv_rc[] = { "/bin/sh", NULL };
static char * envp_rc[] = { "HOME=/", NULL };

static char * argv[] = { "-/bin/sh",NULL };
static char * envp[] = { "HOME=/usr/root", NULL };

void init(void)
{
 int pid,i;

 执行setup系统调用,读取硬盘信息
 setup((void *) &drive_info);
 打开终端/dev/tty0,以读写方式打开
 (void) open("/dev/tty0",O_RDWR,0);
 复制文件描述符0到标准输出
 (void) dup(0);
 复制文件描述符0到标准出错
 (void) dup(0);
 打印高速缓存的信息,以1024字节为单位
 printf("%d buffers = %d bytes buffer space/n/r",NR_BUFFERS,
  NR_BUFFERS*BLOCK_SIZE);
 
 printf("Free mem: %d bytes/n/r",memory_end-main_memory_start);
 在进程1中创建子进程
 if (!(pid=fork())) {
  创建成功之后,在子进程中执行/etc/rc中的命令
  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) {
  在init进程中创建子进程
  if ((pid=fork())<0) {
   printf("Fork failed in init/r/n");
   continue;
  }
  if (!pid) {
   为新创建的子进程创建一个新的会话期,执行shell.
   close(0);close(1);close(2);
   setsid();
   设置标准输入,标准输出和标准出错
   (void) open("/dev/tty0",O_RDWR,0);
   (void) dup(0);
   (void) dup(0);
   执行交互式shell。
   _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);
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值