嵌入式Linux内核时钟初始化问题

内核版本:linux 2.6.18
平台: for arm
搞清rtc在kernel内的作用:
linux系统有两个时钟:一个是由主板电池驱动的“real time clock”也叫做rtc或者叫cmos时钟,
硬件时钟。当操作系统关机的时候,用这个来记录时间,但是对于运行的系统是不用这个时间的。
另一个时间是 “system clock”也叫内核时钟或者软件时钟,是由软件根据时间中断来进行计数的,
内核时钟在系统关机的情况下是不存在的,所以,当操作系统启动的时候,内核时钟是要读取rtc时间
来进行时间同步。并且在系统关机的时候将系统时间写回rtc中进行同步。
如前所述,linux内核与rtc进行互操作的时机只有两个:
1) 内核在启动时从rtc中读取启动时的时间与日期;
2) 内核在需要时将时间与日期回写到rtc中。
系统启动时,内核通过读取rtc来初始化内核时钟,又叫墙上时间,该时间放在xtime变量中。
the current time of day (the wall time) is defined in kernel/timer.c:
struct timespec xtime;
the timespec data structure is defined in as:
struct timespec {
        time_t tv_sec;               /* seconds */
        long tv_nsec;                /* nanoseconds */
};
问题1:系统启动时在哪读取rtc的值并设置内核时钟进行时间同步的呢?
最有可能读取rtc设置内核时钟的位置应该在arch/arm/kernel/time.c里的time_init函数内.
time.c为系统的时钟驱动部分.time_init函数会在系统初始化时,由init/main.c里的start_kernel函数内调用.x86架构就是在这里读rtc值并初始化系统时钟xtime的.
arm架构的time_init代码如下:
/* arch/arm/kernel/time.c */
void __init time_init(void)
{
 if (system_timer->offset == null)
  system_timer->offset = dummy_gettimeoffset;
 system_timer->init();
#ifdef config_no_idle_hz
 if (system_timer->dyn_tick)
  system_timer->dyn_tick->lock = spin_lock_unlocked;
#endif
}
上面system_timer->init()实际执行的是时钟驱动体系架构相关(具体平台)部分定义的init函数,若是s3c2410平台,则执行的为arch/arm/mach-s3c2410/time.c里定义的s3c2410_timer_init函数.不过s3c2410_timer_init()也没有读rtc的代码.整个时钟驱动初始化的过程大致就执行这些代码.
既然在系统时钟驱动初始化的过程中没有读rtc值并设置内核时钟,那会在哪设置呢?
我搜了一下,发现内核好象只有在arch/cris/kernel/time.c里有rtc相关代码,如下: 
/* arch/cris/kernel/time.c */
/* grab the time from the rtc chip */
//读rtc的函数
unsigned long get_cmos_time(void)
{
unsigned int year, mon, day, hour, min, sec;
sec = cmos_read(rtc_seconds);
min = cmos_read(rtc_minutes);
hour = cmos_read(rtc_hours);
day = cmos_read(rtc_day_of_month);
mon = cmos_read(rtc_month);
…………
return mktime(year, mon, day, hour, min, sec);
}
这个函数会在update_xtime_from_cmos内被调用:
void update_xtime_from_cmos(void)
{
if(have_rtc) {
  xtime.tv_sec = get_cmos_time();
  xtime.tv_nsec = 0;
}
}
另外还有设置rtc的函数
int set_rtc_mmss(unsigned long nowtime); /* write time into rtc chip */
不过我加了printk测试了一下,好象arch/cris/kernel/time.c这个文件和这两个函数只是适用与x86?
arm平台启动时并不走这边.因此执行不到这些函数。
那arm平台启动时,系统是在哪读rtc的值并对内核时钟(walltime)进行初始化的呢?
已解决:
嵌入式linux内核(arm)是在系统启动时执行/etc/init.d/hwclock.sh脚本,这个脚本会调用hwclock小程序读取rtc的值并设置系统时钟。
(换句话说,这要取决于你制作的文件系统里是否有这样的脚本)
/* /etc/init.d/hwclock.sh */
daemon1=/sbin/hwclock
start() {
    local ret error=
    [ ! -f /etc/adjtime ] &&  echo 0.0 0 0.0 > /etc/adjtime
    log_status_msg setting the system clock using the hardware clock as reference... -n
    # copies hardware clock time to system clock using the correct
    # timezone for hardware clocks in local time, and sets kernel
    # timezone. do not remove.
    [ $hwclockaccess != no ] && $daemon1 --hctosys $gmt $badyear
    #
    # now that /usr/share/zoneinfo should be available,
    # announce the local time.
    #
    log_status_msg system clock set. local time: `date`
    log_status_msg
    return 0
}
hwclock最先读取的设备文件是 /dev/rtc  ,busybox里面的hwclock是这样实现的:
static int xopen_rtc(int flags)
{
 int rtc;
 if (!rtcname) {
  rtc = open(/dev/rtc, flags);
  if (rtc >= 0)
   return rtc;
  rtc = open(/dev/rtc0, flags);
  if (rtc >= 0)
   return rtc;
  rtcname = /dev/misc/rtc;
 }
 return xopen(rtcname, flags);
}
2. 内核如何更新rtc时钟?
通过set_rtc函数指针指向的函数,set_rtc在arch/arm/kernel/time.c内
/* arch/arm/kernel/time.c */
/*
 * hook for setting the rtc's idea of the current time.
 */
int (*set_rtc)(void);
但是set_rtc函数指针在哪初始化的呢?set_rtc应该是和rtc驱动相关的函数.
搜索kernel源码后发现,好象内核其他地方并没有对其初始化。待解决!
set_rtc在do_set_rtc内调用
static inline void do_set_rtc(void)
{
 ……
 if (set_rtc())
  /*
   * rtc update failed.  try again in 60s
   */
  next_rtc_update = xtime.tv_sec + 60;
 else
  next_rtc_update = xtime.tv_sec + 660; /* update every ~11 minutes by default*/
}
do_set_rtc在timer_tick里调用
/*
 * kernel system timer support. 
 */
void timer_tick(struct pt_regs *regs)
{
 profile_tick(cpu_profiling, regs);
 do_leds();
 do_set_rtc();
 do_timer(1);
 ……
}
timer_tick为kernel提供的体系架构无关的时钟中断处理函数,通常会在体系架构相关的时钟中断处理函数内调用它。如s3c2410是这样的:
在arch/arm/mach-s3c2410/time.c中
 * irq handler for the timer
 */
static irqreturn_t
s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
 write_seqlock(&xtime_lock);
 timer_tick(regs);
 write_sequnlock(&xtime_lock);
 return irq_handled;
}

CAD中如何将dwg图纸输出为高分辨率图像
示波器探头参数,你了解多少?
人工智能70年 科幻和现实的交融
Adasky研发的热成像摄像头技术用于驾驶辅助系统和自动驾驶车辆
小米路由器高端新品将成为小米11的最佳搭档
嵌入式Linux内核时钟初始化问题
学了这些射频圈“黑话”,咱们就是射频人
PLC的恒压供水系统整体设计及工作原理
一种结合选择性浸出和固相煅烧的回收工艺
物联网产业的五大核心发展详解
区块链将催动“无现金支付”时代来临
贸泽电子新品推荐:2021全年推出近70000个新物料率先引入新品的全球分销商
全球车企遇缺“芯”之痛,国产芯片替代提上日程
从AI发展时间表回顾人工智能的历史
特斯拉机器学习超级计算机DOJO支持灵活适应新的算法和应用
深圳先进院研制出黑磷光纤传感器 实现对重金属离子的超灵敏检测
宝能汽车集团赋能观致汽车,观致汽车未来可期
曝特斯拉计划在中国大规模扩张充电基础设施
发动机前后油封气密性检测装置的设计
AI比我们想得更加以人类为中心