Linux-0.11 入口函数main.c详解

news/2024/11/25 21:38:13/

Linux-0.11 入口函数main.c详解

模块简介

main.c大部分代码主要是对内核进行初始化,而main.c开始,就都是c语言编写的内核了。

函数详解

time_init

static void time_init(void)

该函数读取CMOS时钟信息作为系统的开机时间。

	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);//调用kernel_mktime构建时间,详情参考Linux-0.11 kernel目录mktime.c详解

main

void main(void)	

在head.s中会跳转main函数中进行执行。

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;
elsebuffer_memory_end = 1*1024*1024;

接下来就是对各个模块进行初始化。其内容在具体的模块都有讲解,这里不再赘述。在这最后,会重新打开中断。

	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();

接下来,将切换到用户态去执行进程0。

	move_to_user_mode();if (!fork()) {		/* we count on this going ok */init();}

在分析move_to_user_mode,我们回顾一下sched_init函数中和进程0相关的部分。

在sched_init函数中设置了进程0的ldt和tss。其中ldt部分的定义如下:

    //ldt{ \{0,0}, \{0x9f,0xc0fa00}, \{0x9f,0xc0f200}, \}, \

其中代码段为{0x0000009f,0x00c0fa00}, 数据段为{0x0000009f,0x00c0f200}

接下来我们依次分析。

首先是代码段,{0x0000009f,0x00c0fa00}, 翻译成二进制,注意是按照小端序列,如下所示:

63-48:00000000 11000000
47-32:11111010 00000000
31-16:00000000 00000000
15-00:00000000 10011111

按照段描述符的定义,代码段的分析结果如下
:
段基址:00000000 00000000 00000000 00000000
段限长:0x009f * 4k

接下来是数据段,{0x0000009f,0x00c0f200}, 翻译成二进制,注意是按照小端序列,如下所示:

63-48:00000000 11000000
47-32:11110010 00000000
31-16:00000000 00000000
15-00:00000000 10011111

按照段描述符的定义,数据段的分析结果如下

段基址:00000000 00000000 00000000 00000000
段限长:0x009f * 4k

由此可以看出,进程0的代码段和数据段都映射到线性地址为0处。

数据段和代码段唯一不同的是TYPE字段不同,代码段是1010,代表是代码段,其可读可执行。数据段是0010,代表数据段,且可读可写。

因此sched_init为这里切换进程0到用户态执行打下了铺垫。

下面我们就来看move_to_user_mode, 其定义如下:

#define move_to_user_mode() \
__asm__ ("movl %%esp,%%eax\n\t" \"pushl $0x17\n\t" \"pushl %%eax\n\t" \"pushfl\n\t" \"pushl $0x0f\n\t" \"pushl $1f\n\t" \"iret\n" \"1:\tmovl $0x17,%%eax\n\t" \"movw %%ax,%%ds\n\t" \"movw %%ax,%%es\n\t" \"movw %%ax,%%fs\n\t" \"movw %%ax,%%gs" \:::"ax")

看到其中使用了iret指令,因此这里其实是模拟了一个中断的压栈情况。其效果就是在iret返回时,使得ss=0x17,cs=0x0f
在这里插入图片描述

接着通过movw指令,将ds、es、fs、gs都设置为0x17。

通过这一番操作,这些寄存器中的DPL都是3了,也就是用户态了。因此,可以这样总结,move_to_user_mode实际就是将cs/ds/es/fs/gs/ss 都设置为用户态的值。

在这最后,进程0开始fork出进程1, 而自己则进入pause,因此进程0又被称为idle进程。

	if (!fork()) {		/* we count on this going ok */init();}for(;;) pause();

init

void init(void)

init进程是系统中真正的第一个进程。

	int pid,i;setup((void *) &drive_info);
	(void) open("/dev/tty0",O_RDWR,0);(void) dup(0);(void) dup(0);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);

执行shell程序,加载/etc/rc

	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\r\n");continue;}if (!pid) {close(0);close(1);close(2);setsid();(void) open("/dev/tty0",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);	/* NOTE! _exit, not exit() */

Q & A


http://www.ppmy.cn/news/101654.html

相关文章

选择交换机主要看哪些参数指标

交换机有几个性能指标您一定要知道哦&#xff0c;和海翎光电的小编一起温故而知新。 网络构成方式&#xff1a;接入层交换机、汇聚层交换机、核心层交换机 OST模型&#xff1a;第二层交换机、第三层交换机、第四层交换机……第七层交换机 交换机的可管理性&#xff1a;可管理…

15-Vue技术栈之创建Vue3.0工程

目录 1.使用 vue-cli 创建2.使用 vite 创建 1.使用 vue-cli 创建 官方文档&#xff1a;https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create ## 查看vue/cli版本&#xff0c;确保vue/cli版本在4.5.0以上 vue --version ## 安装或者升级你的vue/cli npm insta…

最常见JS加密保护代码的方法

当谈到JavaScript&#xff08;简称JS&#xff09;代码的保护时&#xff0c;加密是一种常见的策略。加密可以帮助保护你的JS代码&#xff0c;防止未经授权的访问、修改和复制。在本文中&#xff0c;我将向你介绍一些常用的js加密保护方法&#xff0c;并提供一些通俗易懂的示例代…

vue实现验证码登陆

我们在使用 vue进行前端开发时&#xff0c;都需要登录验证&#xff0c;而在登录的过程中&#xff0c;用户需要输入自己的用户名和密码&#xff0c;如果是输错的话还需要进行再次输入。这样不仅容易造成用户密码泄露&#xff0c;还会影响用户体验。因此在我们的系统中都会存在验…

自动驾驶汽车的安全技术特点

“安全第一”是自动驾驶的核心理念和价值观。 自动驾驶车辆的整体系统安全设计是一项复杂的系统工程&#xff0c; 涉及车载自动驾驶系统的核心算法策略设计、 硬件和软件冗余安全设计、远程云代驾技术、 全流程测试验证技术等&#xff0c; 并遵循功能安全&#xff08;ISO 2626…

第三方apple pencil哪个好?好用的电容笔排行榜

由于Apple Pencil的推出&#xff0c;让iPad变成了一个轻量化的办公室工具&#xff0c;它的优点就是可以让画家在iPad上作画&#xff0c;能够适用于各种各样的绘画&#xff0c;并且非常适合一些上班族。今天就来为大家推荐几支适合画画的电容笔&#xff01; 第一部分、电容笔选…

5.5G,通信产业下一个分水岭?

通信领域的变化日新月异&#xff0c;在5G商用渐次铺开之后&#xff0c;5.5G比6G先行到来。 5月28日获悉&#xff0c;近日北京移动首个5G-A实验基站在昌平区的国际信息港建设开通&#xff0c;引发业内关注。业内观点认为&#xff0c;5.5G是5G和6G之间的过渡“台阶”&#xff0c;…

Linux系统编程 进程相关概念

1. 进程相关概念 程序(Program)”是一个静态的概念&#xff0c;一般对应于操作系统中的一个可执行文件 执行中的程序叫做进程(Process)&#xff0c;是一个动态的概念 ,现代的操作系统都可以同时启动多个进程。 程序&#xff1a;死的。只占用磁盘空间。 ——剧本。 进程&#xf…