当前位置: 首页 > news >正文

【linux V0.11】init/main.c

文章目录

  • void main(void)
  • move_to_user_mode
  • _syscall
    • fork()
  • void init(void)
  • 其他

void main(void)

#define EXT_MEM_K(∗(unsignedshort∗)0x90002//1MB以后的扩展内存大小(KB)。
#define DRIVE_NFO(∗(structdrive info∗)0x90080//硬盘参数表基址。
#define ORIG_ROOT_DEV(∗(unsignedshort∗)0x901FC//根文件系统所在设备号。struct drive_info { char dummy[32]; } drive_info;//用于存放硬盘参数表信息
void main(void)
{ROOT_DEV = ORIG_ROOT_DEV;				//根设备号 →ROOT DEVdrive_info = DRIVE_INFO;memory_end = (1<<20) + (EXT_MEM_K<<10);	//内存大小=1MB+扩展内存(KB)∗1024。memory_end &= 0xfffff000;				//内存大小页对齐,忽略不到4KB(1页)的内存数if (memory_end > 16*1024*1024)			//如果内存超过 16MB,则限制最大可用内存为 16MBmemory_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;elsebuffer_memory_end = 1*1024*1024;main_memory_start = buffer_memory_end;	//主内存从缓冲区之后开始分配
#ifdef RAMDISK			//如果定义了虚拟盘,则初始化虚拟盘。此时主内存将减少main_memory_start += rd_init(main_memory_start, RAMDISK*1024);
#endifmem_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()) {init();	//创建第一个用户态进程 init,它是所有后续进程的祖先进程。}//task0(空闲进程),是唯一一个可以在没有收到信号的情况下被唤醒的任务。for(;;) pause();	//进入 idle 循环 pause()
}

move_to_user_mode

内核在初始化结束时“切换”到初始任务0。
模拟中断调用返回过程,即利用指令iret运行初始任务0。

首先设置堆栈,模拟刚 进入中断调用过程时(具有特权层切换的) 堆栈的内容布置情况。
move_to_user_mode

movl %esp,%eax	//将当前堆栈指针 esp 保存到 eax,这是用户态堆栈的地址(即内核栈当前的位置)
pushl $0x17		//首先将Task0堆栈段选择符(SS)入栈
pushl %eax		//将 eax(即用户栈指针)压入栈中
pushfl			//将当前标志寄存器压栈,保存状态
pushl $0x0f		//将Task0代码段选择符(cs)入栈。
pushl $1f		//将下面标号1的偏移地址(eip)入栈。
iret
1:	movl $0x17,%eax	//设置用户态的段寄存器,都设置为 0x17,即用户数据段选择符movw %ax,%dsmovw %ax, %esmovw %ax,%fsmovw %ax,%gs

_syscall

这些宏的作用是让用户程序通过 int $0x80 指令触发中断,进入内核态,从而调用相应的内核函数。
_syscall0处理无参数,_syscall1处理一个参数,以此类推。
用户程序不能直接访问硬件或执行特权指令 ,必须通过“系统调用”来请求内核完成任务。

//内核实现的系统调用符号常数,用作系统调用函数表中的索引值
#define __NR_setup	0	/* used only by init, to get system going */
#define __NR_exit	1
#define __NR_fork	2
#define __NR_read	3
...#define _syscall0(type,name)
type name(void)
{long __res;__asm__ volatile ("int $0x80"	//调用系统中断0x80: "=a" (__res)				//返回值==>eax( res)。: "0" (__NR_##name));		//输入为系统中断调用号 NR nameif (__res >= 0)return (type) __res;		//如果返回值>=0,则直接返回该值errno = -__res;					//否则置出错号,并返回-1return -1;
}

当用户态执行 int $0x80 后,CPU 会跳转到内核中的中断处理入口(_system_call)。Linux 内核根据sys_call_table和传入的系统调用号(索引)找到对应的处理函数。

fork()

static inline _syscall0(int,fork)
fork
首先调用C函数find_empty_process(),取得一个进程号pid。若返回负数则说明目前任务数组已
#满。然后调用copy_process()复制进程。

_sys_fork:call _find_empty_process	//查找空进程槽testl %eax,%eaxjs 1fpush %gspushl %esipushl %edipushl %ebppushl %eaxcall _copy_process			//调用copy_process()复制进程addl $20,%esp
1:	ret

具体内容以后再看。

void init(void)

init()函数运行在任务0创建的子进程(任务1)中。它首先对第一个要执行的程序(shell)的环境进行初始化,然后加载该程序并执行之。

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;//sys_setup,读取硬盘参数包括分区表信息并建立虚拟盘和安装根文件系统设备。setup((void *) &drive_info);//用读写访问方式打开设备“/dev/tty0”,这里对应终端控制台。返回的句柄0号———stdin标准输入设备(void) open("/dev/tty0",O_RDWR,0);(void) dup(0);	//复制句柄,产生句柄1号———stdout标准输出设备。(void) dup(0);	//复制句柄,产生句柄2号———stderr标准出错输出设备。printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS,NR_BUFFERS*BLOCK_SIZE);//打印缓冲区块数和总字节数,每块1024字节printf("Free mem: %d bytes\n\r",memory_end-main_memory_start);////空闲内存字节数//fork()用于创建一个子进程(子任务)。//对于被创建的子进程,fork()将返回0值,对于原(父进程)将返回子进程的进程号。if (!(pid=fork())) {//子进程执行的内容close(0);//该子进程关闭了句柄0(stdin)if (open("/etc/rc",O_RDONLY,0))//以只读方式打开/etc/rc文件_exit(1);execve("/bin/sh",argv_rc,envp_rc);//执行/bin/sh程序_exit(2);}//wait()是等待子进程停止或终止,其返回值应是子进程的进程号(pid)。//父进程等待子进程的结束。//&i是存放返回状态信息的位置。如果wait()返回值不等于子进程号,则继续等待。if (pid>0)while (pid != wait(&i));//如果执行到这里,说明刚创建的子进程的执行已停止或终止了。while (1) {//先再创建一个子进程,如果出错,打印信息后继续fork()。if ((pid=fork())<0) {printf("Fork failed in init\r\n");continue;}if (!pid) {close(0);close(1);close(2);//关闭所有以前还遗留的句柄(stdin,stdout,stderr)//新创建一个会话并设置进程组号,然后重新打开/dev/tty0作为stdin,并复制成stdout和stderr。setsid();(void) open("/dev/tty0",O_RDWR,0);(void) dup(0);(void) dup(0);_exit(execve("/bin/sh",argv,envp));//再次执行系统解释程序,但是参数环境与上次不一样}//父进程再次运行wait()等待while (1)if (pid == wait(&i))break;//如果子进程又停止了执行,打印信息,继续重试printf("\n\rchild %d died with code %04x\n\r",pid,i);sync();}_exit(0);	/* NOTE! _exit, not exit() */
}

其他

main.c还有关于时间的初始化一些内容,ez


文章转载自:
http://bemoisten.riewr.cn
http://biforked.riewr.cn
http://anecdotic.riewr.cn
http://calchas.riewr.cn
http://caulocaline.riewr.cn
http://atomix.riewr.cn
http://abjection.riewr.cn
http://chiaroscurist.riewr.cn
http://bmd.riewr.cn
http://broadways.riewr.cn
http://berimbau.riewr.cn
http://cavy.riewr.cn
http://boner.riewr.cn
http://assumingly.riewr.cn
http://atelic.riewr.cn
http://aigret.riewr.cn
http://azorean.riewr.cn
http://analogy.riewr.cn
http://asciferous.riewr.cn
http://biblicist.riewr.cn
http://appd.riewr.cn
http://armoured.riewr.cn
http://arteriosclerosis.riewr.cn
http://biotope.riewr.cn
http://blahs.riewr.cn
http://amerika.riewr.cn
http://bituminise.riewr.cn
http://catercorner.riewr.cn
http://archbishopric.riewr.cn
http://botargo.riewr.cn
http://www.dtcms.com/a/281747.html

相关文章:

  • 函数指针与指针函数练习讲解
  • 9、线程理论1
  • HostVDS 云服务器测评:平价入门、流媒体解锁全美、表现稳定
  • 暑假Python基础整理 --异常处理及程序调试
  • Redis 中的持久化机制:RDB 与 AOF
  • Java之Stream其二
  • 第二章 OB 存储引擎高级技术
  • 数学金融与金融工程:学科差异与选择指南
  • 【AI News | 20250714】每日AI进展
  • 为 Git branch 命令添加描述功能
  • 将 Vue 3 + Vite + TS 项目打包为 .exe 文件
  • 711SJBH构建制造业信息化人才培训体系的对策-开题报告
  • 21-C#的委托简单使用-1
  • Datawhale 25年7月组队学习coze-ai-assistant Task1学习笔记:动手实践第一个AI Agent—英伦生活口语陪练精灵
  • yolov5、yolov8、yolov11、yolov12如何训练及轻量化部署-netron-onnx
  • echarts折线图的 线条的样式怎么控制
  • Python os模块完全指南:从入门到实战
  • python编程实现GUI界面的排序与查找算法动态模拟演示程序
  • Sa-Token使用要点
  • mongoDB安装初始化及简单介绍
  • 2025/7/15——java学习总结
  • Pandas 和 NumPy 使用文档整理
  • 大宗现货电子盘交易系统核心功能代码解析
  • QT6 源,六章事件系统(8)QEvent 的孙子类:QEnterEvent 光标进入
  • 无穿戴动捕如何凭借摄像头视觉识别算法,赋能高校专业教学革新?
  • python进阶
  • 145-变分模态分解VMD与平稳小波变换SWT信号降噪算法实现!
  • 4G模块 A7680通过MQTT协议连接到onenet(新版)
  • WebAPIs基本认知,DOM基础介绍
  • 基于Springboot+UniApp+Ai实现模拟面试小工具五:权限校验参数校验及日志功能实现