第17回 | 原来操作系统获取时间的方式也这么 low
共 5346字,需浏览 11分钟
·
2022-01-17 00:15
新读者看这里,老读者直接跳过。
本系列会以一个读小说的心态,从开机启动后的代码执行顺序,带着大家阅读和赏析 Linux 0.11 全部核心代码,了解操作系统的技术细节和设计思想。
你会跟着我一起,看着一个操作系统从啥都没有开始,一步一步最终实现它复杂又精巧的设计,读完这个系列后希望你能发出感叹,原来操作系统源码就是这破玩意。
以下是已发布文章的列表,详细了解本系列可以先从开篇词看起。
第一部分 进入内核前的苦力活
第二部分 大战前期的初始化工作
本系列的 GitHub 地址如下(文末阅读原文可直接跳转)
https://github.com/sunym1993/flash-linux0.11-talk
------- 正文开始 -------
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();
}
#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);
}
#define CMOS_READ(addr) ({ \
outb_p(0x80|addr,0x70); \
inb_p(0x71); \
})
端口 | 读 | 写 |
---|---|---|
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 | 命令寄存器或状态寄存器 | 命令寄存器 |
在 0x1F2 写入要读取的扇区数
在 0x1F3 ~ 0x1F6 这四个端口写入计算好的起始 LBA 地址
在 0x1F7 处写入读命令的指令号
不断检测 0x1F7 (此时已成为状态寄存器的含义)的忙位
如果第四步骤为不忙,则开始不断从 0x1F0 处读取数据到内存指定位置,直到读完
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);
}
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;
}
所以至少到目前来说,你还不应该感觉操作系统有多么的“高端”,很多时候都是繁琐地,读人家的硬件手册,获取到想要的的信息,拿来给自己用,或者对其进行各种设置。
但你一定要耐得住寂寞,真正体现操作系统的强大设计之处,还得接着往下读。
欲知后事如何,且听下回分解。
------- 关于本系列 -------
本系列的开篇词看这
本系列的扩展资料看这(也可点击阅读原文),这里有很多有趣的资料、答疑、互动参与项目,持续更新中,希望有你的参与。
https://github.com/sunym1993/flash-linux0.11-talk
本系列全局视角
最后,祝大家都能追更到系列结束,只要你敢持续追更,并且把每一回的内容搞懂,我就敢让你在系列结束后说一句,我对 Linux 0.11 很熟悉。
公众号更新系列文章不易,阅读量越来越低,希望大家多多传播,不方便的话点个小小的赞我也会很开心,谢谢大家咯。
另外,本系列完全免费,希望大家能多多传播给同样喜欢的人,同时给我的 GitHub 项目点个 star,就在阅读原文处,这些就足够让我坚持写下去了!我们下回见。