首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

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

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

首先搞清楚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);
}
继承事业,薪火相传
返回列表