linux0.11内核源码修仙传第九章——时间初始化

devtools/2025/3/26 10:57:53/

🚀 前言

    本文主要解释了计算机断电重启后能准确读取时间的原因,内容很短,对应于书中的第17回。希望各位给个三连,拜托啦,这对我真的很重要!!!

目录

  • 🚀 前言
  • 🏆 计算机时间从哪里来
  • 🏆 时间初始化
  • 🎯总结
  • 📖参考资料

🏆 计算机时间从哪里来

    熟悉嵌入式的都知道硬件上有一个模块叫实时时钟(Real Time Clock,RTC),也叫CMOS时钟。这个模块的电源是独立的,采用纽扣电池供电。当操作系统关机时,就用这个来记录时间。其工作原理类似电子手表,通过石英晶体振荡记录时间流逝。

🏆 时间初始化

    知道了上电后时间从哪里来后,我们只需要关注内核中如何获取即可。内核中时间初始化的源码如下:

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就是读取CMOS的数据,分别是年,月,日,小时,分钟,秒;BCD_TO_BIN就是将BCD码(CMOS RAM中存放数据的编码格式)转换为我们常用的二进制。

    首先是CMOS_READ函数:

#define CMOS_READ(addr) ({ \
outb_p(0x80|addr,0x70); \
inb_p(0x71); \
})

    可以看到这个宏函数是先写再读,实际上这也是CPU与外设交互的做法,都是通过端口写入值让外设干嘛,再从另一个端口读值接收外设的反馈。按照CMOS手册要求的读写端口进行读写即可,就像上面代码的循环里面一样。

    接下来看BCD_TO_BIN 函数:

#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)

    由于是BCD码,即四位表示十进制的一位,因此首先先把后四位与15(0b1111)做与运算,后面将前面4位后移并乘10表示十位,最后将十位与个位进行相加。

    最后还有一个函数:

long kernel_mktime(struct tm * tm)
{long res;int year;year = tm->tm_year - 70;
/* magic offsets (y+1) needed to get leapyears right.*/res = YEAR*year + DAY*((year+1)/4);res += month[tm->tm_mon];
/* and (y+2) here. If it wasn't a leap-year, we have to adjust */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;
}

    这个函数在时间初始化的最后,这就是一个简单的换算,目的是为了计算从1970年1月1日0时起至开机当前经过的秒数,作为开机时间存储在变量中。

🎯总结

    本文是一个很简单的模块——时间初始化。其核心就是CPU访问外设是通过端口的,先向端口写入一个指令表示我要干什么,然后再去另一个端口读取反馈数据。


📖参考资料

[1] linux源码趣读
[2] 一个64位操作系统的设计与实现
[3] Linux内核的时间管理


http://www.ppmy.cn/devtools/171328.html

相关文章

【微服务架构】本地负载均衡的实现(基于随机算法)

前言 负载均衡 概念:一种将网络流量或业务请求均匀分配到多个服务器或服务实例上的技术,旨在提高系统的可用性、性能和可伸缩性。作用: 提高性能:通过将请求分散到多个实例上,避免单个实例因请求过多而过载&#xff…

GMII 接口

文章目录 概述硬件拓扑GMII 接口站管理接口发送数据时序接收数据时序参考 本文为笔者学习以太网对网上资料归纳整理所做的笔记,文末均附有参考链接,如侵权,请联系删除。 概述 GMII 是千兆网的MII接口,这个也有相应的 RGMII 接口&…

笔试专题(三)

文章目录 字符串中找出连续最长的数字串题解代码 拼三角题解代码 字符串中找出连续最长的数字串 题目链接 题解 1. 考察双指针 模拟 2. 算法思路:给定一个i 0,让i,如果遇到数字字符就创建一个变量j i,让j去遍历&#xff0c…

Rust从入门到精通之进阶篇:20.项目实践

项目实践 在本章中,我们将把前面学到的所有 Rust 知识整合起来,构建一个完整的应用程序。通过实际项目,你将学习如何组织代码、处理依赖关系、实现功能以及测试和部署 Rust 应用程序。我们将构建一个命令行待办事项管理器(Todo CLI),它具有添加、列出、完成和删除任务的…

深入理解指针(2)(C语言版)

文章目录 前言一、数组名的理解二、使用指针访问数组三、一维数组传参的本质四、冒泡排序五、二级指针六、指针数组七、指针数组模拟二维数组总结 前言 在上一篇文章中,我们初步了解了指针的基本概念和用法。今天,我们将继续深入探索指针在数组、函数传…

Uniapp使用大疆SDK打包离线原生插件二

上一篇讲了如何下载及配置原生插件,今天深入的了解下如何将java代码的SDK引入Uniapp 一、配置libs: 在Android开发中,libs目录通常用于存放项目所需的第三方库文件。 将sdk中的包lib.5plus.base-release.aar、android-gif-drawable-release1.2.23.aa…

日志截断/日志中途清空/不停止程序

使用场景: nohup ./abc.sh > 123.log 2>&1 & 若想在不停止程序的前提下减小 123.log 的占用空间或者对日志进行分割,可采用如下方法: 1. 手动截断日志 可以手动截断日志文件,把文件内容清空,但保留文…

100天精通Python(爬虫篇)——第122天:基于selenium接管已启动的浏览器(反反爬策略)

文章目录 1、问题描述2、问题推测3、解决方法3.1 selenium自动启动浏览器3.2 selenium接管已启动的浏览器3.3 区别总结4、代码实战4.1 手动方法(手动打开浏览器输入账号密码)4.2 自动方法(.bat文件启动的浏览器)1、问题描述 使用selenium自动化测试爬取pdd的时候,通过携带…