【linux】【操作系统】初始化程序之main.c源码阅读

在这里插入图片描述

/init/main.c是Linux操作系统启动过程的核心部分,它负责初始化硬件、设备、内存和系统服务,以及启动第一个用户进程,为后续的系统运行奠定基础。

详细解析

1. 内联函数定义
  • fork, pause, setup, sync: 这些函数被声明为内联,意味着它们在编译时会被直接嵌入到调用点,而不是通过常规函数调用的方式执行。这在内核上下文中特别重要,因为避免了不必要的栈操作和上下文切换,提高了效率。尤其是forkpause,由于它们在main函数中的关键作用,需要确保不会破坏栈的完整性。
1.1 fork内联函数分析

系统调用宏定义

#define __NR_setup	0	/* used only by init, to get system going */
#define __NR_exit	1
#define __NR_fork	2
#define _syscall0(type,name) \
type name(void) \
{
   
    \
long __res; \
__asm__ volatile ("int $0x80" \
	: "=a" (__res) \
	: "0" (__NR_##name)); \
if (__res >= 0) \
	return (type) __res; \
errno = -__res; \
return -1; \
}

此宏定义 _syscall0 的功能是简化创建无参数系统调用函数的过程,其具体作用如下:

  1. 参数解析:
    • type: 指定系统调用函数的返回值类型。
    • name: 系统调用函数的名称。
  2. 函数体详解:
    • 定义一个长整型变量 __res 用于存储系统调用的结果。
    • 使用内联汇编 __asm__ 插入一条 int $0x80 指令,这是 Linux 中触发系统调用的标准方式。
    • 汇编指令使用寄存器传递参数和接收结果,其中 "=a" (__res) 表示将结果存储到 eax 寄存器(即 __res),而 "0" (__NR_##name) 表示从 eax 寄存器读取系统调用编号,这里 __NR_##name 是根据 name 动态生成的系统调用编号。
  3. 错误处理:
    • 如果系统调用成功,即 __res >= 0,则将 __res 转换为 type 类型并返回。
    • 如果系统调用失败,即 __res < 0,则将 -__res 的值赋给全局变量 errno,表示错误代码,并返回 -1
1.2 setup内联函数分析

这个宏提供了一种便捷方式来封装系统调用,避免了每次手动编写相似的汇编代码和错误处理逻辑。例如,可以这样使用:_syscall1(int, read, int, fd), 生成一个 read 函数,用于读取文件描述符 fd 的数据。

#define _syscall1(type,name,atype,a) \
type name(atype a) \
{
   
    \
long __res; \
__asm__ volatile ("int $0x80" \
	: "=a" (__res) \
	: "0" (__NR_##name),"b" ((long)(a))); \
if (__res >= 0) \
	return (type) __res; \
errno = -__res; \
return -1; \
}
  1. 参数解析:

    • type: 指定系统调用返回值的数据类型。
    • name: 系统调用函数的名称。
    • atype: 系统调用单个参数的数据类型。
    • a: 系统调用的参数。
  2. 功能实现:

    • 定义了一个函数 name 接受参数 a 类型为 atype
    • 使用内嵌汇编指令 "int $0x80" 触发 Linux 系统调用机制。
    • __NR_##name 是系统调用编号,它根据 name 动态生成,如 __NR_open 对应 open 系统调用的编号。
    • 参数 a 被传递到寄存器 b 中,供系统调用使用。
    • 调用结果存储在 __res 变量中。
    • 如果 __res 大于等于 0,表示系统调用成功,将 __res 强制转换为 type 类型并返回。
    • 如果 __res 小于 0,表示系统调用失败,将 -__res 的值赋给全局变量 errno 表示错误码,函数返回 -1
2. 系统初始化与配置
  • 硬件与内存初始化:

    • EXT_MEM_KDRIVE_INFO 用于读取系统BIOS提供的扩展内存信息和磁盘驱动器信息。
    • memory_end, buffer_memory_end, main_memory_start: 这些变量用于确定系统可用的内存范围,以及分配给缓冲区的内存大小。根据系统总内存的不同,分配给缓冲区的内存也会相应调整。
  • 实时钟初始化 (time_init)

    • 通过访问CMOS寄存器读取系统时间,然后将其从二进制编码的十进制(BCD)格式转换为二进制格式,最后计算出系统启动的时间戳。
3. 设备与资源初始化
  • hd_init, floppy_init, blk_dev_init, chr_dev_init: 这些函数分别用于初始化硬盘、软盘、块设备和字符设备,确保系统可以访问和管理这些硬件资源。
3.1 hd_init分析

此函数主要负责硬盘设备的初始化工作,确保系统可以正确地与硬盘交互。

void hd_init(void)
{
   
   
	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
	set_intr_gate(0x2E,&hd_interrupt);
	outb_p(inb_p(0x21)&0xfb,0x21);
	outb(inb_p(0xA1)&0xbf,0xA1);
}

blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;

这一行代码将硬盘设备的请求处理函数设置为 DEVICE_REQUEST。在Linux设备驱动模型中,blk_dev 是一个数组,存储了所有注册的块设备信息。MAJOR_NR 表示硬盘设备的主设备号,request_fn 是该设备结构体中的一个成员,用于指定当有I/O请求到达时应该调用哪个函数来处理这些请求。这里的 DEVICE_REQUEST 就是这个处理函数,它负责调度和执行具体的读写操作。

set_intr_gate(0x2E, &hd_interrupt);

#define _set_gate(gate_addr,type,dpl,addr) \
__asm__ ("movw %%dx,%%ax\n\t" \
	"movw %0,%%dx\n\t" \
	"movl %%eax,%1\n\t" \
	"movl %%edx,%2" 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值