发布日期:2022-06-18 17:01 点击次数:160
书接上回,上回书我们说到,通过启动化纵脱台的 tty_init 操作,内核代码不错很便捷地在纵脱台输出字符啦!
当作用户也不错通过敲击键盘,或调用诸如 printf 这样的库函数,在屏幕上输出信息,同期维持换行和滚屏等友好计划,这些都是 tty_init 启动化,以及其对外封装的小功能函数,来结束的。
我们陆续往下看下一个启动化的苦难鬼,time_init。
void main(void) { ... 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()) {init();} for(;;) pause(); }
也曾我很酷爱,操作系统是何如获取到现时技艺的呢?
固然,目下都联网了,不错从收罗上及时同步。那当莫得收罗时,为什么操作系统在启动之后,不错走漏出现时技艺呢?难道操作系统在电脑关机后,依然禁止地在某处运行着,勤死力恳数着秒表么?
固然不是,那我们今天就掀开这个 time_init 函数一探究竟。
掀开这个函数后我又是很振作,因为很短,且莫得更潜入的措施调用。
#define CMOS_READ(addr) ({ \ outb_p(0x80|addr,0x70); \ inb_p(0x71); \ }) #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) 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); }
渴望的代码呀!
那主要便是对 CMOS_READ 和 BCD_TO_BIN 都是啥原理伸开讲一下就明显明晰。
率先是 CMOS_READ
#define CMOS_READ(addr) ({ \ outb_p(0x80|addr,0x70); \ inb_p(0x71); \ })
便是对一个端口先 out 写一下,再 in 读一下。
这是 CPU 与外设交互的一个基本玩法,CPU 与外设打交道基本是通过端口,往某些端口写值来暗示要这个外设干嘛,然后从另一些端口读值来接收外设的反映。
至于这个外设里面是何如结束的,对使用它的操作系统而言,是个黑盒,无需照拂。那关于我们尺度员来说,就更无谓照拂了。
对 CMOS 这个外设的交互讲起来可能没嗅觉, 被男狂揉吃奶胸60分钟视频我们望望与硬盘的交互。
最常见的便是读硬盘了,我们看硬盘的端口表。
端口 读 写
0x1F0
数据寄存器 数据寄存器0x1F1
舛讹寄存器 特征寄存器0x1F2
扇区计数寄存器 扇区计数寄存器0x1F3
扇区号寄存器或 LBA 块地址 0~7 扇区号或 LBA 块地址 0~7 0x1F4 磁道数低 8 位或 LBA 块地址 8~15 磁道数低 8 位或 LBA 块地址 8~15 0x1F5 磁道数高 8 位或 LBA 块地址 16~23 磁道数高 8 位或 LBA 块地址 16~23 0x1F6 驱动器/磁头或 LBA 块地址 24~27 驱动器/磁头或 LBA 块地址 24~27 0x1F7 敕令寄存器或情景寄存器 敕令寄存器那读硬盘便是,往除了第一个之外的背面几个端口写数据,告诉要读硬盘的哪个扇区,读几许。然后再从 0x1F0 端口一个字节一个字节的读数据。这就完成了一次硬盘读操作。
若是以为不够具体,那来个具体的版块。
在 0x1F2 写入要读取的扇区数 在 0x1F3 ~ 0x1F6 这四个端口写入料到好的肇端 LBA 地址 在 0x1F7 处写入读敕令的请示号 赓续检测 0x1F7 (此时已成为情景寄存器的含义)的忙位 若是第四设施为不忙,则登程点赓续从 0x1F0 处读取数据到内存指定位置,直到读完看,是不是对 CPU 最底层是若何与外设打交道有点嗅觉了?是不是也不难?便是按照人家的操作手册,然后无脑按照条款读写端口就行了。
固然,读取硬盘的这个无脑轮回,不错 CPU 班师读取并做写入内存的操作,这样就会占用 CPU 的料到资源。
也不错交给 DMA 设立去读,自如 CPU,但和硬盘的交互,肉丝肉足丝袜人妻在线无码通通都是按照硬件手册上的端口讲解,来操作的,本色上亦然做了一层封装。
好了,我们仍是学会了和一个外设打交道的基本玩法了。
那我们代码中要打交道的是哪个外设呢?便是 CMOS。
它是主板上的一个可读写的 RAM 芯片,你在开机时长按某个键就不错插足树立它的页面。
那我们的代码,其实便是与它打交道,获取它的一些数据费力。
我们回尽头看代码。
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); }
前边几个赋值语句 CMOS_READ 便是通过读写 CMOS 上的指定端口,挨次获取年月日时候秒等信息。具体咋操作代码上也写了,亦然按照 CMOS 手册条款的读写指定端口就行了,我们就不伸开了。
是以你看,其实操作系统尺度,亦然要依靠与一个外部设立打交道,来获取这些信息的,并不是它我方有什么魔力。操作系统最大的魔力,就在于它借力完成了一项伟大的事,借 CPU 的力,借硬盘的力,借内存的力,以及目下借 CMOS 的力。
至于 CMOS 又是若何清楚技艺的,这个就不在我们商量限制了。
接下来 BCD_TO_BIN 便是 BCD 革新成 BIN,因为从 CMOS 上获取的这些年月日都是 BCD 码值,需要革新成存储在我们变量上的二进制数值,是以需要一个小算法来革新一下,没什么原理。
临了一步 kernel_mktime 也很浮浅,便是把柄刚刚的那些时候秒数据,料到从 1970 年 1 月 1 日 0 时起到开机其时经由的秒数,当作开机技艺,存储在 startup_time 这个变量里。
想量度不错仔细望望这段代码,不外我以为这种细节不必看。
startup_time = kernel_mktime(&time); // kernel/mktime.c long kernel_mktime(struct tm * tm) { long res; int year; year = tm->tm_year - 70; res = YEAR*year + DAY*((year+1)/4); res += month[tm->tm_mon]; if (tm->tm_mon>1 && ((year+2)%4)) res -= DAY; res += DAY*(tm->tm_mday-1); res += HOUR*tm->tm_hour; res += MINUTE*tm->tm_min; res += tm->tm_sec; return res; }
就这。
是以今天其实便是,料到出了一个 startup_time 变量费力,至于这个变量今后会被谁用,何如用,那便是后话了。
确信你缓缓也体会到了,此时操作系统好多场所都是用外设条款的款式去商榷,比如硬盘信息、走漏模式,以及今天的开机技艺的获取等。
是致使少到目下来说,你还不应该嗅觉操作系统有何等的“高端”,好多时候都是繁琐地,读人家的硬件手册,获取到想要的的信息,拿来给我方用,大概对其进行多样树立。
但你一定要耐得住孤单,真实体现操作系统的高大计划之处,还得接着往下读。
欲知后事若何,且听下回瓦解。
本文转载自微信公众号「低并发编程」,不错通过以下二维码关注。转载本文请有关低并发编程公众号。本网站已赢得低并发编程的授权。
Powered by 最近2019中文字幕在线高清 @2013-2022 RSS地图 HTML地图