无翼乌邪恶之色彩女教师我们接续往下看下一个运改革的疼痛鬼

发布日期:2022-04-22 20:46    点击次数:143

无翼乌邪恶之色彩女教师

书接上回,上回书我们说到,通过运改革完结台的 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 这个外设的交互讲起来可能没嗅觉,我们望望与硬盘的交互。

最常见的等于读硬盘了,我们看硬盘的端口表。

 

 

端口 读 写

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 手册条件的读写指定端口就行了,我们就不张开了。

第一代移动通信技术始于上世纪80年代,从1G时代发展到目前的5G时代,移动通信基本每隔10年就要升级一代。而每当新一代移动通信开始商用时,更新一代移动通信的研究就已开始启动,因为它需要大约10年时间才能商用。

因此,5G前传选择xWDM技术为主已成为共识。而三大运营商选择建立不同的5G前传标准:中国移动的Open-WDM/MWDM、中国电信的LWDM和中国联通的G.metro/DWDM方案。

很多网友表示困惑:5G我还没体验上呢,马上要来6G了?6G跑那么快有必要吗?

是以你看,其实操作系统行为,亦然要依靠与一个外部诞生打交道,来获取这些信息的,并不是它我方有什么魔力。操作系统最大的魔力,就在于它借力完成了一项伟大的事,借 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 变量费力,至于这个变量今后会被谁用,奈何用,那等于后话了。

服气你逐步也体会到了,此时操作系统好多所在都是用外设条件的神色去参议,比如硬盘信息、清楚情势,以及今天的开机时代的获取等。

是甚至少到目下来说,你还不应该嗅觉操作系统有何等的“高端”,好多时候都是繁琐地,读人家的硬件手册,获取到想要的的信息,拿来给我方用,约略对其进行各式建树。

但你一定要耐得住孤单,确凿体现操作系统的宏大野心之处,还得接着往下读。

欲知后事若何,且听下回剖释。

本文转载自微信公众号「低并发编程」,不错通过以下二维码关注。转载本文请相干低并发编程公众号。本网站已赢得低并发编程的授权。