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 <linux/time.h> 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;

  }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值